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/command_line.h"
8 #include "base/files/file_util.h"
9 #include "base/memory/scoped_ptr.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/frame_navigation_entry.h"
16 #include "content/browser/frame_host/navigation_controller_impl.h"
17 #include "content/browser/frame_host/navigation_entry_impl.h"
18 #include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
19 #include "content/browser/frame_host/navigation_request.h"
20 #include "content/browser/frame_host/navigator.h"
21 #include "content/browser/frame_host/navigator_impl.h"
22 #include "content/browser/site_instance_impl.h"
23 #include "content/browser/web_contents/web_contents_impl.h"
24 #include "content/common/frame_messages.h"
25 #include "content/common/view_messages.h"
26 #include "content/public/browser/navigation_details.h"
27 #include "content/public/browser/notification_registrar.h"
28 #include "content/public/browser/notification_types.h"
29 #include "content/public/browser/render_view_host.h"
30 #include "content/public/browser/web_contents_delegate.h"
31 #include "content/public/browser/web_contents_observer.h"
32 #include "content/public/common/content_switches.h"
33 #include "content/public/common/page_state.h"
34 #include "content/public/common/page_type.h"
35 #include "content/public/common/url_constants.h"
36 #include "content/public/test/mock_render_process_host.h"
37 #include "content/public/test/test_notification_tracker.h"
38 #include "content/public/test/test_utils.h"
39 #include "content/test/test_render_frame_host.h"
40 #include "content/test/test_render_view_host.h"
41 #include "content/test/test_web_contents.h"
42 #include "net/base/net_util.h"
43 #include "skia/ext/platform_canvas.h"
44 #include "testing/gtest/include/gtest/gtest.h"
50 // Creates an image with a 1x1 SkBitmap of the specified |color|.
51 gfx::Image
CreateImage(SkColor color
) {
53 bitmap
.allocN32Pixels(1, 1);
54 bitmap
.eraseColor(color
);
55 return gfx::Image::CreateFrom1xBitmap(bitmap
);
58 // Returns true if images |a| and |b| have the same pixel data.
59 bool DoImagesMatch(const gfx::Image
& a
, const gfx::Image
& b
) {
60 // Assume that if the 1x bitmaps match, the images match.
61 SkBitmap a_bitmap
= a
.AsBitmap();
62 SkBitmap b_bitmap
= b
.AsBitmap();
64 if (a_bitmap
.width() != b_bitmap
.width() ||
65 a_bitmap
.height() != b_bitmap
.height()) {
68 SkAutoLockPixels
a_bitmap_lock(a_bitmap
);
69 SkAutoLockPixels
b_bitmap_lock(b_bitmap
);
70 return memcmp(a_bitmap
.getPixels(),
72 a_bitmap
.getSize()) == 0;
75 class MockScreenshotManager
: public content::NavigationEntryScreenshotManager
{
77 explicit MockScreenshotManager(content::NavigationControllerImpl
* owner
)
78 : content::NavigationEntryScreenshotManager(owner
),
79 encoding_screenshot_in_progress_(false) {
82 ~MockScreenshotManager() override
{}
84 void TakeScreenshotFor(content::NavigationEntryImpl
* entry
) {
86 bitmap
.allocPixels(SkImageInfo::Make(
87 1, 1, kAlpha_8_SkColorType
, kPremul_SkAlphaType
));
88 bitmap
.eraseARGB(0, 0, 0, 0);
89 encoding_screenshot_in_progress_
= true;
90 OnScreenshotTaken(entry
->GetUniqueID(), bitmap
, content::READBACK_SUCCESS
);
91 WaitUntilScreenshotIsReady();
94 int GetScreenshotCount() {
95 return content::NavigationEntryScreenshotManager::GetScreenshotCount();
98 void WaitUntilScreenshotIsReady() {
99 if (!encoding_screenshot_in_progress_
)
101 message_loop_runner_
= new content::MessageLoopRunner
;
102 message_loop_runner_
->Run();
106 // Overridden from content::NavigationEntryScreenshotManager:
107 void TakeScreenshotImpl(content::RenderViewHost
* host
,
108 content::NavigationEntryImpl
* entry
) override
{}
110 void OnScreenshotSet(content::NavigationEntryImpl
* entry
) override
{
111 encoding_screenshot_in_progress_
= false;
112 NavigationEntryScreenshotManager::OnScreenshotSet(entry
);
113 if (message_loop_runner_
.get())
114 message_loop_runner_
->Quit();
117 scoped_refptr
<content::MessageLoopRunner
> message_loop_runner_
;
118 bool encoding_screenshot_in_progress_
;
120 DISALLOW_COPY_AND_ASSIGN(MockScreenshotManager
);
127 // TimeSmoother tests ----------------------------------------------------------
129 // With no duplicates, GetSmoothedTime should be the identity
131 TEST(TimeSmoother
, Basic
) {
132 NavigationControllerImpl::TimeSmoother smoother
;
133 for (int64 i
= 1; i
< 1000; ++i
) {
134 base::Time t
= base::Time::FromInternalValue(i
);
135 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
139 // With a single duplicate and timestamps thereafter increasing by one
140 // microsecond, the smoothed time should always be one behind.
141 TEST(TimeSmoother
, SingleDuplicate
) {
142 NavigationControllerImpl::TimeSmoother smoother
;
143 base::Time t
= base::Time::FromInternalValue(1);
144 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
145 for (int64 i
= 1; i
< 1000; ++i
) {
146 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1);
147 t
= base::Time::FromInternalValue(i
);
148 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
152 // With k duplicates and timestamps thereafter increasing by one
153 // microsecond, the smoothed time should always be k behind.
154 TEST(TimeSmoother
, ManyDuplicates
) {
155 const int64 kNumDuplicates
= 100;
156 NavigationControllerImpl::TimeSmoother smoother
;
157 base::Time t
= base::Time::FromInternalValue(1);
158 for (int64 i
= 0; i
< kNumDuplicates
; ++i
) {
159 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1);
160 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
162 for (int64 i
= 1; i
< 1000; ++i
) {
163 base::Time expected_t
=
164 base::Time::FromInternalValue(i
+ kNumDuplicates
);
165 t
= base::Time::FromInternalValue(i
);
166 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
170 // If the clock jumps far back enough after a run of duplicates, it
171 // should immediately jump to that value.
172 TEST(TimeSmoother
, ClockBackwardsJump
) {
173 const int64 kNumDuplicates
= 100;
174 NavigationControllerImpl::TimeSmoother smoother
;
175 base::Time t
= base::Time::FromInternalValue(1000);
176 for (int64 i
= 0; i
< kNumDuplicates
; ++i
) {
177 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1000);
178 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
180 t
= base::Time::FromInternalValue(500);
181 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
184 // NavigationControllerTest ----------------------------------------------------
186 class NavigationControllerTest
187 : public RenderViewHostImplTestHarness
,
188 public WebContentsObserver
{
190 NavigationControllerTest() : navigation_entry_committed_counter_(0) {
193 void SetUp() override
{
194 RenderViewHostImplTestHarness::SetUp();
195 WebContents
* web_contents
= RenderViewHostImplTestHarness::web_contents();
196 ASSERT_TRUE(web_contents
); // The WebContents should be created by now.
197 WebContentsObserver::Observe(web_contents
);
200 // WebContentsObserver:
201 void DidStartNavigationToPendingEntry(
203 NavigationController::ReloadType reload_type
) override
{
204 navigated_url_
= url
;
207 void NavigationEntryCommitted(
208 const LoadCommittedDetails
& load_details
) override
{
209 navigation_entry_committed_counter_
++;
212 const GURL
& navigated_url() const {
213 return navigated_url_
;
216 NavigationControllerImpl
& controller_impl() {
217 return static_cast<NavigationControllerImpl
&>(controller());
220 bool HasNavigationRequest() {
221 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
222 switches::kEnableBrowserSideNavigation
)) {
223 return contents()->GetFrameTree()->root()->navigation_request() !=
226 return process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID
)
230 const GURL
GetLastNavigationURL() {
231 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
232 switches::kEnableBrowserSideNavigation
)) {
233 NavigationRequest
* navigation_request
=
234 contents()->GetFrameTree()->root()->navigation_request();
235 CHECK(navigation_request
);
236 return navigation_request
->common_params().url
;
238 const IPC::Message
* message
=
239 process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID
);
241 Tuple
<CommonNavigationParams
, StartNavigationParams
,
242 RequestNavigationParams
> nav_params
;
243 FrameMsg_Navigate::Read(message
, &nav_params
);
244 return get
<0>(nav_params
).url
;
249 size_t navigation_entry_committed_counter_
;
252 void RegisterForAllNavNotifications(TestNotificationTracker
* tracker
,
253 NavigationController
* controller
) {
254 tracker
->ListenFor(NOTIFICATION_NAV_LIST_PRUNED
,
255 Source
<NavigationController
>(controller
));
256 tracker
->ListenFor(NOTIFICATION_NAV_ENTRY_CHANGED
,
257 Source
<NavigationController
>(controller
));
260 class TestWebContentsDelegate
: public WebContentsDelegate
{
262 explicit TestWebContentsDelegate() :
263 navigation_state_change_count_(0),
264 repost_form_warning_count_(0) {}
266 int navigation_state_change_count() {
267 return navigation_state_change_count_
;
270 int repost_form_warning_count() {
271 return repost_form_warning_count_
;
274 // Keep track of whether the tab has notified us of a navigation state change.
275 void NavigationStateChanged(WebContents
* source
,
276 InvalidateTypes changed_flags
) override
{
277 navigation_state_change_count_
++;
280 void ShowRepostFormWarningDialog(WebContents
* source
) override
{
281 repost_form_warning_count_
++;
285 // The number of times NavigationStateChanged has been called.
286 int navigation_state_change_count_
;
288 // The number of times ShowRepostFormWarningDialog() was called.
289 int repost_form_warning_count_
;
292 // -----------------------------------------------------------------------------
294 TEST_F(NavigationControllerTest
, Defaults
) {
295 NavigationControllerImpl
& controller
= controller_impl();
297 EXPECT_FALSE(controller
.GetPendingEntry());
298 EXPECT_FALSE(controller
.GetVisibleEntry());
299 EXPECT_FALSE(controller
.GetLastCommittedEntry());
300 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
301 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), -1);
302 EXPECT_EQ(controller
.GetEntryCount(), 0);
303 EXPECT_FALSE(controller
.CanGoBack());
304 EXPECT_FALSE(controller
.CanGoForward());
307 TEST_F(NavigationControllerTest
, GoToOffset
) {
308 NavigationControllerImpl
& controller
= controller_impl();
309 TestNotificationTracker notifications
;
310 RegisterForAllNavNotifications(¬ifications
, &controller
);
312 const int kNumUrls
= 5;
313 std::vector
<GURL
> urls(kNumUrls
);
314 for (int i
= 0; i
< kNumUrls
; ++i
) {
315 urls
[i
] = GURL(base::StringPrintf("http://www.a.com/%d", i
));
318 main_test_rfh()->SendRendererInitiatedNavigationRequest(urls
[0], true);
319 main_test_rfh()->PrepareForCommit();
320 main_test_rfh()->SendNavigate(0, urls
[0]);
321 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
322 navigation_entry_committed_counter_
= 0;
323 EXPECT_EQ(urls
[0], controller
.GetVisibleEntry()->GetVirtualURL());
324 EXPECT_FALSE(controller
.CanGoBack());
325 EXPECT_FALSE(controller
.CanGoForward());
326 EXPECT_FALSE(controller
.CanGoToOffset(1));
328 for (int i
= 1; i
<= 4; ++i
) {
329 main_test_rfh()->SendRendererInitiatedNavigationRequest(urls
[i
], true);
330 main_test_rfh()->PrepareForCommit();
331 main_test_rfh()->SendNavigate(i
, urls
[i
]);
332 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
333 navigation_entry_committed_counter_
= 0;
334 EXPECT_EQ(urls
[i
], controller
.GetVisibleEntry()->GetVirtualURL());
335 EXPECT_TRUE(controller
.CanGoToOffset(-i
));
336 EXPECT_FALSE(controller
.CanGoToOffset(-(i
+ 1)));
337 EXPECT_FALSE(controller
.CanGoToOffset(1));
340 // We have loaded 5 pages, and are currently at the last-loaded page.
344 GO_TO_MIDDLE_PAGE
= -2,
347 GO_TO_BEGINNING
= -2,
352 const int test_offsets
[NUM_TESTS
] = {
360 for (int test
= 0; test
< NUM_TESTS
; ++test
) {
361 int offset
= test_offsets
[test
];
362 controller
.GoToOffset(offset
);
364 // Check that the GoToOffset will land on the expected page.
365 EXPECT_EQ(urls
[url_index
], controller
.GetPendingEntry()->GetVirtualURL());
366 main_test_rfh()->PrepareForCommit();
367 main_test_rfh()->SendNavigate(url_index
, urls
[url_index
]);
368 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
369 navigation_entry_committed_counter_
= 0;
370 // Check that we can go to any valid offset into the history.
371 for (size_t j
= 0; j
< urls
.size(); ++j
)
372 EXPECT_TRUE(controller
.CanGoToOffset(j
- url_index
));
373 // Check that we can't go beyond the beginning or end of the history.
374 EXPECT_FALSE(controller
.CanGoToOffset(-(url_index
+ 1)));
375 EXPECT_FALSE(controller
.CanGoToOffset(urls
.size() - url_index
));
379 TEST_F(NavigationControllerTest
, LoadURL
) {
380 NavigationControllerImpl
& controller
= controller_impl();
381 TestNotificationTracker notifications
;
382 RegisterForAllNavNotifications(¬ifications
, &controller
);
384 const GURL
url1("http://foo1");
385 const GURL
url2("http://foo2");
388 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
389 // Creating a pending notification should not have issued any of the
390 // notifications we're listening for.
391 EXPECT_EQ(0U, notifications
.size());
393 // The load should now be pending.
394 EXPECT_EQ(controller
.GetEntryCount(), 0);
395 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), -1);
396 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
397 EXPECT_FALSE(controller
.GetLastCommittedEntry());
398 ASSERT_TRUE(controller
.GetPendingEntry());
399 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetVisibleEntry());
400 EXPECT_FALSE(controller
.CanGoBack());
401 EXPECT_FALSE(controller
.CanGoForward());
402 EXPECT_EQ(contents()->GetMaxPageID(), -1);
404 // Neither the timestamp nor the status code should have been set yet.
405 EXPECT_TRUE(controller
.GetPendingEntry()->GetTimestamp().is_null());
406 EXPECT_EQ(0, controller
.GetPendingEntry()->GetHttpStatusCode());
408 // We should have gotten no notifications from the preceeding checks.
409 EXPECT_EQ(0U, notifications
.size());
411 main_test_rfh()->PrepareForCommit();
412 main_test_rfh()->SendNavigate(0, url1
);
413 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
414 navigation_entry_committed_counter_
= 0;
416 // The load should now be committed.
417 EXPECT_EQ(controller
.GetEntryCount(), 1);
418 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
419 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
420 EXPECT_TRUE(controller
.GetLastCommittedEntry());
421 EXPECT_FALSE(controller
.GetPendingEntry());
422 ASSERT_TRUE(controller
.GetVisibleEntry());
423 EXPECT_FALSE(controller
.CanGoBack());
424 EXPECT_FALSE(controller
.CanGoForward());
425 EXPECT_EQ(contents()->GetMaxPageID(), 0);
426 EXPECT_EQ(0, controller
.GetLastCommittedEntry()->bindings());
428 // The timestamp should have been set.
429 EXPECT_FALSE(controller
.GetVisibleEntry()->GetTimestamp().is_null());
433 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
435 // The load should now be pending.
436 EXPECT_EQ(controller
.GetEntryCount(), 1);
437 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
438 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
439 EXPECT_TRUE(controller
.GetLastCommittedEntry());
440 ASSERT_TRUE(controller
.GetPendingEntry());
441 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetVisibleEntry());
442 // TODO(darin): maybe this should really be true?
443 EXPECT_FALSE(controller
.CanGoBack());
444 EXPECT_FALSE(controller
.CanGoForward());
445 EXPECT_EQ(contents()->GetMaxPageID(), 0);
447 EXPECT_TRUE(controller
.GetPendingEntry()->GetTimestamp().is_null());
449 // Simulate the beforeunload ack for the cross-site transition, and then the
451 main_test_rfh()->PrepareForCommit();
452 contents()->GetPendingMainFrame()->SendNavigate(1, url2
);
453 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
454 navigation_entry_committed_counter_
= 0;
456 // The load should now be committed.
457 EXPECT_EQ(controller
.GetEntryCount(), 2);
458 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
459 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
460 EXPECT_TRUE(controller
.GetLastCommittedEntry());
461 EXPECT_FALSE(controller
.GetPendingEntry());
462 ASSERT_TRUE(controller
.GetVisibleEntry());
463 EXPECT_TRUE(controller
.CanGoBack());
464 EXPECT_FALSE(controller
.CanGoForward());
465 EXPECT_EQ(contents()->GetMaxPageID(), 1);
467 EXPECT_FALSE(controller
.GetVisibleEntry()->GetTimestamp().is_null());
472 base::Time
GetFixedTime(base::Time time
) {
478 TEST_F(NavigationControllerTest
, LoadURLSameTime
) {
479 NavigationControllerImpl
& controller
= controller_impl();
480 TestNotificationTracker notifications
;
481 RegisterForAllNavNotifications(¬ifications
, &controller
);
483 // Set the clock to always return a timestamp of 1.
484 controller
.SetGetTimestampCallbackForTest(
485 base::Bind(&GetFixedTime
, base::Time::FromInternalValue(1)));
487 const GURL
url1("http://foo1");
488 const GURL
url2("http://foo2");
491 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
493 main_test_rfh()->PrepareForCommit();
494 main_test_rfh()->SendNavigate(0, url1
);
495 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
496 navigation_entry_committed_counter_
= 0;
500 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
502 // Simulate the beforeunload ack for the cross-site transition, and then the
504 main_test_rfh()->PrepareForCommit();
505 contents()->GetPendingMainFrame()->SendNavigate(1, url2
);
506 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
507 navigation_entry_committed_counter_
= 0;
509 // The two loads should now be committed.
510 ASSERT_EQ(controller
.GetEntryCount(), 2);
512 // Timestamps should be distinct despite the clock returning the
515 controller
.GetEntryAtIndex(0)->GetTimestamp().ToInternalValue());
517 controller
.GetEntryAtIndex(1)->GetTimestamp().ToInternalValue());
520 void CheckNavigationEntryMatchLoadParams(
521 NavigationController::LoadURLParams
& load_params
,
522 NavigationEntryImpl
* entry
) {
523 EXPECT_EQ(load_params
.url
, entry
->GetURL());
524 EXPECT_EQ(load_params
.referrer
.url
, entry
->GetReferrer().url
);
525 EXPECT_EQ(load_params
.referrer
.policy
, entry
->GetReferrer().policy
);
526 EXPECT_EQ(load_params
.transition_type
, entry
->GetTransitionType());
527 EXPECT_EQ(load_params
.extra_headers
, entry
->extra_headers());
529 EXPECT_EQ(load_params
.is_renderer_initiated
, entry
->is_renderer_initiated());
530 EXPECT_EQ(load_params
.base_url_for_data_url
, entry
->GetBaseURLForDataURL());
531 if (!load_params
.virtual_url_for_data_url
.is_empty()) {
532 EXPECT_EQ(load_params
.virtual_url_for_data_url
, entry
->GetVirtualURL());
534 if (NavigationController::UA_OVERRIDE_INHERIT
!=
535 load_params
.override_user_agent
) {
536 bool should_override
= (NavigationController::UA_OVERRIDE_TRUE
==
537 load_params
.override_user_agent
);
538 EXPECT_EQ(should_override
, entry
->GetIsOverridingUserAgent());
540 EXPECT_EQ(load_params
.browser_initiated_post_data
.get(),
541 entry
->GetBrowserInitiatedPostData());
542 EXPECT_EQ(load_params
.transferred_global_request_id
,
543 entry
->transferred_global_request_id());
546 TEST_F(NavigationControllerTest
, LoadURLWithParams
) {
547 NavigationControllerImpl
& controller
= controller_impl();
549 NavigationController::LoadURLParams
load_params(GURL("http://foo"));
550 load_params
.referrer
=
551 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault
);
552 load_params
.transition_type
= ui::PAGE_TRANSITION_GENERATED
;
553 load_params
.extra_headers
= "content-type: text/plain";
554 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
555 load_params
.is_renderer_initiated
= true;
556 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
557 load_params
.transferred_global_request_id
= GlobalRequestID(2, 3);
559 controller
.LoadURLWithParams(load_params
);
560 NavigationEntryImpl
* entry
= controller
.GetPendingEntry();
562 // The timestamp should not have been set yet.
564 EXPECT_TRUE(entry
->GetTimestamp().is_null());
566 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
569 TEST_F(NavigationControllerTest
, LoadURLWithExtraParams_Data
) {
570 NavigationControllerImpl
& controller
= controller_impl();
572 NavigationController::LoadURLParams
load_params(
573 GURL("data:text/html,dataurl"));
574 load_params
.load_type
= NavigationController::LOAD_TYPE_DATA
;
575 load_params
.base_url_for_data_url
= GURL("http://foo");
576 load_params
.virtual_url_for_data_url
= GURL(url::kAboutBlankURL
);
577 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_FALSE
;
579 controller
.LoadURLWithParams(load_params
);
580 NavigationEntryImpl
* entry
= controller
.GetPendingEntry();
582 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
585 TEST_F(NavigationControllerTest
, LoadURLWithExtraParams_HttpPost
) {
586 NavigationControllerImpl
& controller
= controller_impl();
588 NavigationController::LoadURLParams
load_params(GURL("https://posturl"));
589 load_params
.transition_type
= ui::PAGE_TRANSITION_TYPED
;
590 load_params
.load_type
=
591 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST
;
592 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
595 const unsigned char* raw_data
=
596 reinterpret_cast<const unsigned char*>("d\n\0a2");
597 const int length
= 5;
598 std::vector
<unsigned char> post_data_vector(raw_data
, raw_data
+length
);
599 scoped_refptr
<base::RefCountedBytes
> data
=
600 base::RefCountedBytes::TakeVector(&post_data_vector
);
601 load_params
.browser_initiated_post_data
= data
.get();
603 controller
.LoadURLWithParams(load_params
);
604 NavigationEntryImpl
* entry
= controller
.GetPendingEntry();
606 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
609 // Tests what happens when the same page is loaded again. Should not create a
610 // new session history entry. This is what happens when you press enter in the
611 // URL bar to reload: a pending entry is created and then it is discarded when
612 // the load commits (because WebCore didn't actually make a new entry).
613 TEST_F(NavigationControllerTest
, LoadURL_SamePage
) {
614 NavigationControllerImpl
& controller
= controller_impl();
615 TestNotificationTracker notifications
;
616 RegisterForAllNavNotifications(¬ifications
, &controller
);
618 const GURL
url1("http://foo1");
621 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
622 EXPECT_EQ(0U, notifications
.size());
623 main_test_rfh()->PrepareForCommit();
624 main_test_rfh()->SendNavigate(0, url1
);
625 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
626 navigation_entry_committed_counter_
= 0;
628 ASSERT_TRUE(controller
.GetVisibleEntry());
629 const base::Time timestamp
= controller
.GetVisibleEntry()->GetTimestamp();
630 EXPECT_FALSE(timestamp
.is_null());
633 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
634 EXPECT_EQ(0U, notifications
.size());
635 main_test_rfh()->PrepareForCommit();
636 main_test_rfh()->SendNavigate(0, url1
);
637 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
638 navigation_entry_committed_counter_
= 0;
640 // We should not have produced a new session history entry.
641 EXPECT_EQ(controller
.GetEntryCount(), 1);
642 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
643 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
644 EXPECT_TRUE(controller
.GetLastCommittedEntry());
645 EXPECT_FALSE(controller
.GetPendingEntry());
646 ASSERT_TRUE(controller
.GetVisibleEntry());
647 EXPECT_FALSE(controller
.CanGoBack());
648 EXPECT_FALSE(controller
.CanGoForward());
650 // The timestamp should have been updated.
652 // TODO(akalin): Change this EXPECT_GE (and other similar ones) to
653 // EXPECT_GT once we guarantee that timestamps are unique.
654 EXPECT_GE(controller
.GetVisibleEntry()->GetTimestamp(), timestamp
);
657 // Load the same page twice, once as a GET and once as a POST.
658 // We should update the post state on the NavigationEntry.
659 TEST_F(NavigationControllerTest
, LoadURL_SamePage_DifferentMethod
) {
660 NavigationControllerImpl
& controller
= controller_impl();
661 TestNotificationTracker notifications
;
662 RegisterForAllNavNotifications(¬ifications
, &controller
);
664 const GURL
url1("http://foo1");
667 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
668 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
671 params
.transition
= ui::PAGE_TRANSITION_TYPED
;
672 params
.is_post
= true;
673 params
.post_id
= 123;
674 params
.page_state
= PageState::CreateForTesting(url1
, false, 0, 0);
675 main_test_rfh()->PrepareForCommit();
676 main_test_rfh()->SendNavigateWithParams(¶ms
);
678 // The post data should be visible.
679 NavigationEntry
* entry
= controller
.GetVisibleEntry();
681 EXPECT_TRUE(entry
->GetHasPostData());
682 EXPECT_EQ(entry
->GetPostID(), 123);
685 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
686 main_test_rfh()->PrepareForCommit();
687 main_test_rfh()->SendNavigate(0, url1
);
689 // We should not have produced a new session history entry.
690 ASSERT_EQ(controller
.GetVisibleEntry(), entry
);
692 // The post data should have been cleared due to the GET.
693 EXPECT_FALSE(entry
->GetHasPostData());
694 EXPECT_EQ(entry
->GetPostID(), 0);
697 // Tests loading a URL but discarding it before the load commits.
698 TEST_F(NavigationControllerTest
, LoadURL_Discarded
) {
699 NavigationControllerImpl
& controller
= controller_impl();
700 TestNotificationTracker notifications
;
701 RegisterForAllNavNotifications(¬ifications
, &controller
);
703 const GURL
url1("http://foo1");
704 const GURL
url2("http://foo2");
707 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
708 EXPECT_EQ(0U, notifications
.size());
709 main_test_rfh()->PrepareForCommit();
710 main_test_rfh()->SendNavigate(0, url1
);
711 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
712 navigation_entry_committed_counter_
= 0;
714 ASSERT_TRUE(controller
.GetVisibleEntry());
715 const base::Time timestamp
= controller
.GetVisibleEntry()->GetTimestamp();
716 EXPECT_FALSE(timestamp
.is_null());
719 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
720 controller
.DiscardNonCommittedEntries();
721 EXPECT_EQ(0U, notifications
.size());
723 // Should not have produced a new session history entry.
724 EXPECT_EQ(controller
.GetEntryCount(), 1);
725 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
726 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
727 EXPECT_TRUE(controller
.GetLastCommittedEntry());
728 EXPECT_FALSE(controller
.GetPendingEntry());
729 ASSERT_TRUE(controller
.GetVisibleEntry());
730 EXPECT_FALSE(controller
.CanGoBack());
731 EXPECT_FALSE(controller
.CanGoForward());
733 // Timestamp should not have changed.
734 EXPECT_EQ(timestamp
, controller
.GetVisibleEntry()->GetTimestamp());
737 // Tests navigations that come in unrequested. This happens when the user
738 // navigates from the web page, and here we test that there is no pending entry.
739 TEST_F(NavigationControllerTest
, LoadURL_NoPending
) {
740 NavigationControllerImpl
& controller
= controller_impl();
741 TestNotificationTracker notifications
;
742 RegisterForAllNavNotifications(¬ifications
, &controller
);
744 // First make an existing committed entry.
745 const GURL
kExistingURL1("http://eh");
747 kExistingURL1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
748 main_test_rfh()->PrepareForCommit();
749 main_test_rfh()->SendNavigate(0, kExistingURL1
);
750 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
751 navigation_entry_committed_counter_
= 0;
753 // Do a new navigation without making a pending one.
754 const GURL
kNewURL("http://see");
755 main_test_rfh()->NavigateAndCommitRendererInitiated(99, kNewURL
);
757 // There should no longer be any pending entry, and the third navigation we
758 // just made should be committed.
759 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
760 navigation_entry_committed_counter_
= 0;
761 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
762 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
763 EXPECT_EQ(kNewURL
, controller
.GetVisibleEntry()->GetURL());
766 // Tests navigating to a new URL when there is a new pending navigation that is
767 // not the one that just loaded. This will happen if the user types in a URL to
768 // somewhere slow, and then navigates the current page before the typed URL
770 TEST_F(NavigationControllerTest
, LoadURL_NewPending
) {
771 NavigationControllerImpl
& controller
= controller_impl();
772 TestNotificationTracker notifications
;
773 RegisterForAllNavNotifications(¬ifications
, &controller
);
775 // First make an existing committed entry.
776 const GURL
kExistingURL1("http://eh");
778 kExistingURL1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
779 main_test_rfh()->PrepareForCommit();
780 main_test_rfh()->SendNavigate(0, kExistingURL1
);
781 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
782 navigation_entry_committed_counter_
= 0;
784 // Make a pending entry to somewhere new.
785 const GURL
kExistingURL2("http://bee");
787 kExistingURL2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
788 EXPECT_EQ(0U, notifications
.size());
790 // After the beforeunload but before it commits...
791 main_test_rfh()->PrepareForCommit();
793 // ... Do a new navigation.
794 const GURL
kNewURL("http://see");
795 main_test_rfh()->SendRendererInitiatedNavigationRequest(kNewURL
, true);
796 main_test_rfh()->PrepareForCommit();
797 contents()->GetMainFrame()->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(1, 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. This will happen if the user hits back, but before that commits,
810 // they navigate somewhere new.
811 TEST_F(NavigationControllerTest
, LoadURL_ExistingPending
) {
812 NavigationControllerImpl
& controller
= controller_impl();
813 TestNotificationTracker notifications
;
814 RegisterForAllNavNotifications(¬ifications
, &controller
);
816 // First make some history.
817 const GURL
kExistingURL1("http://foo/eh");
819 kExistingURL1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
820 main_test_rfh()->PrepareForCommit();
821 main_test_rfh()->SendNavigate(0, kExistingURL1
);
822 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
823 navigation_entry_committed_counter_
= 0;
825 const GURL
kExistingURL2("http://foo/bee");
827 kExistingURL2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
828 main_test_rfh()->PrepareForCommit();
829 main_test_rfh()->SendNavigate(1, kExistingURL2
);
830 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
831 navigation_entry_committed_counter_
= 0;
833 // Now make a pending back/forward navigation. The zeroth entry should be
836 EXPECT_EQ(0U, notifications
.size());
837 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
838 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
840 // Before that commits, do a new navigation.
841 const GURL
kNewURL("http://foo/see");
842 main_test_rfh()->SendRendererInitiatedNavigationRequest(kNewURL
, true);
843 main_test_rfh()->PrepareForCommit();
844 main_test_rfh()->SendNavigate(3, kNewURL
);
846 // There should no longer be any pending entry, and the third navigation we
847 // just made should be committed.
848 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
849 navigation_entry_committed_counter_
= 0;
850 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
851 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
852 EXPECT_EQ(kNewURL
, controller
.GetVisibleEntry()->GetURL());
855 // Tests navigating to a new URL when there is a pending back/forward
856 // navigation to a cross-process, privileged URL. This will happen if the user
857 // hits back, but before that commits, they navigate somewhere new.
858 TEST_F(NavigationControllerTest
, LoadURL_PrivilegedPending
) {
859 NavigationControllerImpl
& controller
= controller_impl();
860 TestNotificationTracker notifications
;
861 RegisterForAllNavNotifications(¬ifications
, &controller
);
863 // First make some history, starting with a privileged URL.
864 const GURL
kExistingURL1("http://privileged");
866 kExistingURL1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
867 // Pretend it has bindings so we can tell if we incorrectly copy it.
868 main_test_rfh()->GetRenderViewHost()->AllowBindings(2);
869 main_test_rfh()->PrepareForCommit();
870 main_test_rfh()->SendNavigate(0, kExistingURL1
);
871 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
872 navigation_entry_committed_counter_
= 0;
874 // Navigate cross-process to a second URL.
875 const GURL
kExistingURL2("http://foo/eh");
877 kExistingURL2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
878 main_test_rfh()->PrepareForCommit();
879 TestRenderFrameHost
* foo_rfh
= contents()->GetPendingMainFrame();
880 foo_rfh
->SendNavigate(1, kExistingURL2
);
881 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
882 navigation_entry_committed_counter_
= 0;
884 // Now make a pending back/forward navigation to a privileged entry.
885 // The zeroth entry should be pending.
887 foo_rfh
->SendBeforeUnloadACK(true);
888 EXPECT_EQ(0U, notifications
.size());
889 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
890 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
891 EXPECT_EQ(2, controller
.GetPendingEntry()->bindings());
893 // Before that commits, do a new navigation.
894 const GURL
kNewURL("http://foo/bee");
895 foo_rfh
->SendRendererInitiatedNavigationRequest(kNewURL
, true);
896 foo_rfh
->PrepareForCommit();
897 foo_rfh
->SendNavigate(3, kNewURL
);
899 // There should no longer be any pending entry, and the third navigation we
900 // just made should be committed.
901 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
902 navigation_entry_committed_counter_
= 0;
903 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
904 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
905 EXPECT_EQ(kNewURL
, controller
.GetVisibleEntry()->GetURL());
906 EXPECT_EQ(0, controller
.GetLastCommittedEntry()->bindings());
909 // Tests navigating to an existing URL when there is a pending new navigation.
910 // This will happen if the user enters a URL, but before that commits, the
911 // current page fires history.back().
912 TEST_F(NavigationControllerTest
, LoadURL_BackPreemptsPending
) {
913 NavigationControllerImpl
& controller
= controller_impl();
914 TestNotificationTracker notifications
;
915 RegisterForAllNavNotifications(¬ifications
, &controller
);
917 // First make some history.
918 const GURL
kExistingURL1("http://foo/eh");
920 kExistingURL1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
921 main_test_rfh()->PrepareForCommit();
922 main_test_rfh()->SendNavigate(0, kExistingURL1
);
923 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
924 navigation_entry_committed_counter_
= 0;
926 const GURL
kExistingURL2("http://foo/bee");
928 kExistingURL2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
929 main_test_rfh()->PrepareForCommit();
930 main_test_rfh()->SendNavigate(1, kExistingURL2
);
931 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
932 navigation_entry_committed_counter_
= 0;
934 // A back navigation comes in from the renderer...
935 controller
.GoToOffset(-1);
937 // ...while the user tries to navigate to a new page...
938 const GURL
kNewURL("http://foo/see");
940 kNewURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
941 EXPECT_EQ(0U, notifications
.size());
942 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
943 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
945 // ...and the back navigation commits.
946 main_test_rfh()->PrepareForCommit();
947 main_test_rfh()->SendNavigate(0, kExistingURL1
);
949 // There should no longer be any pending entry, and the back navigation should
951 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
952 navigation_entry_committed_counter_
= 0;
953 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
954 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
955 EXPECT_EQ(kExistingURL1
, controller
.GetVisibleEntry()->GetURL());
958 // Tests an ignored navigation when there is a pending new navigation.
959 // This will happen if the user enters a URL, but before that commits, the
960 // current blank page reloads. See http://crbug.com/77507.
961 TEST_F(NavigationControllerTest
, LoadURL_IgnorePreemptsPending
) {
962 NavigationControllerImpl
& controller
= controller_impl();
963 TestNotificationTracker notifications
;
964 RegisterForAllNavNotifications(¬ifications
, &controller
);
966 // Set a WebContentsDelegate to listen for state changes.
967 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
968 EXPECT_FALSE(contents()->GetDelegate());
969 contents()->SetDelegate(delegate
.get());
971 // Without any navigations, the renderer starts at about:blank.
972 const GURL
kExistingURL(url::kAboutBlankURL
);
974 // Now make a pending new navigation.
975 const GURL
kNewURL("http://eh");
977 kNewURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
978 EXPECT_EQ(0U, notifications
.size());
979 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
980 EXPECT_TRUE(controller
.GetPendingEntry());
981 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
982 EXPECT_EQ(1, delegate
->navigation_state_change_count());
984 // Before that commits, a document.write and location.reload can cause the
985 // renderer to send a FrameNavigate with page_id -1.
986 main_test_rfh()->SendRendererInitiatedNavigationRequest(kExistingURL
, true);
987 main_test_rfh()->PrepareForCommit();
988 main_test_rfh()->SendNavigate(-1, kExistingURL
);
990 // This should clear the pending entry and notify of a navigation state
991 // change, so that we do not keep displaying kNewURL.
992 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
993 EXPECT_FALSE(controller
.GetPendingEntry());
994 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
995 EXPECT_EQ(2, delegate
->navigation_state_change_count());
997 contents()->SetDelegate(NULL
);
1000 // Tests that the pending entry state is correct after an abort.
1001 // We do not want to clear the pending entry, so that the user doesn't
1002 // lose a typed URL. (See http://crbug.com/9682.)
1003 TEST_F(NavigationControllerTest
, LoadURL_AbortDoesntCancelPending
) {
1004 NavigationControllerImpl
& controller
= controller_impl();
1005 TestNotificationTracker notifications
;
1006 RegisterForAllNavNotifications(¬ifications
, &controller
);
1008 // Set a WebContentsDelegate to listen for state changes.
1009 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
1010 EXPECT_FALSE(contents()->GetDelegate());
1011 contents()->SetDelegate(delegate
.get());
1013 // Start with a pending new navigation.
1014 const GURL
kNewURL("http://eh");
1016 kNewURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1017 main_test_rfh()->PrepareForCommit();
1018 EXPECT_EQ(0U, notifications
.size());
1019 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1020 EXPECT_TRUE(controller
.GetPendingEntry());
1021 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
1022 EXPECT_EQ(1, delegate
->navigation_state_change_count());
1024 // It may abort before committing, if it's a download or due to a stop or
1025 // a new navigation from the user.
1026 FrameHostMsg_DidFailProvisionalLoadWithError_Params params
;
1027 params
.error_code
= net::ERR_ABORTED
;
1028 params
.error_description
= base::string16();
1029 params
.url
= kNewURL
;
1030 params
.showing_repost_interstitial
= false;
1031 main_test_rfh()->OnMessageReceived(
1032 FrameHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
1035 // This should not clear the pending entry or notify of a navigation state
1036 // change, so that we keep displaying kNewURL (until the user clears it).
1037 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1038 EXPECT_TRUE(controller
.GetPendingEntry());
1039 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
1040 EXPECT_EQ(1, delegate
->navigation_state_change_count());
1041 NavigationEntry
* pending_entry
= controller
.GetPendingEntry();
1043 // Ensure that a reload keeps the same pending entry.
1044 controller
.Reload(true);
1045 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1046 EXPECT_TRUE(controller
.GetPendingEntry());
1047 EXPECT_EQ(pending_entry
, controller
.GetPendingEntry());
1048 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
1050 contents()->SetDelegate(NULL
);
1053 // Tests that the pending URL is not visible during a renderer-initiated
1054 // redirect and abort. See http://crbug.com/83031.
1055 TEST_F(NavigationControllerTest
, LoadURL_RedirectAbortDoesntShowPendingURL
) {
1056 NavigationControllerImpl
& controller
= controller_impl();
1057 TestNotificationTracker notifications
;
1058 RegisterForAllNavNotifications(¬ifications
, &controller
);
1060 // First make an existing committed entry.
1061 const GURL
kExistingURL("http://foo/eh");
1062 controller
.LoadURL(kExistingURL
, content::Referrer(),
1063 ui::PAGE_TRANSITION_TYPED
, std::string());
1064 main_test_rfh()->PrepareForCommit();
1065 main_test_rfh()->SendNavigate(1, kExistingURL
);
1066 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1067 navigation_entry_committed_counter_
= 0;
1069 // Set a WebContentsDelegate to listen for state changes.
1070 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
1071 EXPECT_FALSE(contents()->GetDelegate());
1072 contents()->SetDelegate(delegate
.get());
1074 // Now make a pending new navigation, initiated by the renderer.
1075 const GURL
kNewURL("http://foo/bee");
1076 NavigationController::LoadURLParams
load_url_params(kNewURL
);
1077 load_url_params
.transition_type
= ui::PAGE_TRANSITION_TYPED
;
1078 load_url_params
.is_renderer_initiated
= true;
1079 controller
.LoadURLWithParams(load_url_params
);
1080 EXPECT_EQ(0U, notifications
.size());
1081 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1082 EXPECT_TRUE(controller
.GetPendingEntry());
1083 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1084 EXPECT_EQ(0, delegate
->navigation_state_change_count());
1086 // The visible entry should be the last committed URL, not the pending one.
1087 EXPECT_EQ(kExistingURL
, controller
.GetVisibleEntry()->GetURL());
1089 // Now the navigation redirects. (There is no corresponding message here.)
1090 const GURL
kRedirectURL("http://foo/see");
1092 // We don't want to change the NavigationEntry's url, in case it cancels.
1093 // Prevents regression of http://crbug.com/77786.
1094 EXPECT_EQ(kNewURL
, controller
.GetPendingEntry()->GetURL());
1096 // It may abort before committing, if it's a download or due to a stop or
1097 // a new navigation from the user.
1098 FrameHostMsg_DidFailProvisionalLoadWithError_Params params
;
1099 params
.error_code
= net::ERR_ABORTED
;
1100 params
.error_description
= base::string16();
1101 params
.url
= kRedirectURL
;
1102 params
.showing_repost_interstitial
= false;
1103 main_test_rfh()->OnMessageReceived(
1104 FrameHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
1107 // Because the pending entry is renderer initiated and not visible, we
1108 // clear it when it fails.
1109 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1110 EXPECT_FALSE(controller
.GetPendingEntry());
1111 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1112 EXPECT_EQ(1, delegate
->navigation_state_change_count());
1114 // The visible entry should be the last committed URL, not the pending one,
1115 // so that no spoof is possible.
1116 EXPECT_EQ(kExistingURL
, controller
.GetVisibleEntry()->GetURL());
1118 contents()->SetDelegate(NULL
);
1121 // Ensure that NavigationEntries track which bindings their RenderViewHost had
1122 // at the time they committed. http://crbug.com/173672.
1123 TEST_F(NavigationControllerTest
, LoadURL_WithBindings
) {
1124 NavigationControllerImpl
& controller
= controller_impl();
1125 TestNotificationTracker notifications
;
1126 RegisterForAllNavNotifications(¬ifications
, &controller
);
1127 std::vector
<GURL
> url_chain
;
1129 const GURL
url1("http://foo1");
1130 const GURL
url2("http://foo2");
1132 // Navigate to a first, unprivileged URL.
1134 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1135 EXPECT_EQ(NavigationEntryImpl::kInvalidBindings
,
1136 controller
.GetPendingEntry()->bindings());
1139 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1140 orig_rfh
->PrepareForCommit();
1141 orig_rfh
->SendNavigate(0, url1
);
1142 EXPECT_EQ(controller
.GetEntryCount(), 1);
1143 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1144 EXPECT_EQ(0, controller
.GetLastCommittedEntry()->bindings());
1146 // Manually increase the number of active frames in the SiteInstance
1147 // that orig_rfh belongs to, to prevent it from being destroyed when
1148 // it gets swapped out, so that we can reuse orig_rfh when the
1149 // controller goes back.
1150 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
1152 // Navigate to a second URL, simulate the beforeunload ack for the cross-site
1153 // transition, and set bindings on the pending RenderViewHost to simulate a
1156 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1157 orig_rfh
->PrepareForCommit();
1158 TestRenderFrameHost
* new_rfh
= contents()->GetPendingMainFrame();
1159 new_rfh
->GetRenderViewHost()->AllowBindings(1);
1160 new_rfh
->SendNavigate(1, url2
);
1162 // The second load should be committed, and bindings should be remembered.
1163 EXPECT_EQ(controller
.GetEntryCount(), 2);
1164 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1165 EXPECT_TRUE(controller
.CanGoBack());
1166 EXPECT_EQ(1, controller
.GetLastCommittedEntry()->bindings());
1168 // Going back, the first entry should still appear unprivileged.
1169 controller
.GoBack();
1170 new_rfh
->PrepareForCommit();
1171 orig_rfh
->SendNavigate(0, url1
);
1172 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1173 EXPECT_EQ(0, controller
.GetLastCommittedEntry()->bindings());
1176 TEST_F(NavigationControllerTest
, Reload
) {
1177 NavigationControllerImpl
& controller
= controller_impl();
1178 TestNotificationTracker notifications
;
1179 RegisterForAllNavNotifications(¬ifications
, &controller
);
1181 const GURL
url1("http://foo1");
1184 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1185 EXPECT_EQ(0U, notifications
.size());
1186 main_test_rfh()->PrepareForCommit();
1187 main_test_rfh()->SendNavigate(0, url1
);
1188 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1189 navigation_entry_committed_counter_
= 0;
1190 ASSERT_TRUE(controller
.GetVisibleEntry());
1191 controller
.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
1192 controller
.Reload(true);
1193 EXPECT_EQ(0U, notifications
.size());
1195 const base::Time timestamp
= controller
.GetVisibleEntry()->GetTimestamp();
1196 EXPECT_FALSE(timestamp
.is_null());
1198 // The reload is pending.
1199 EXPECT_EQ(controller
.GetEntryCount(), 1);
1200 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1201 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1202 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1203 EXPECT_TRUE(controller
.GetPendingEntry());
1204 EXPECT_FALSE(controller
.CanGoBack());
1205 EXPECT_FALSE(controller
.CanGoForward());
1206 // Make sure the title has been cleared (will be redrawn just after reload).
1207 // Avoids a stale cached title when the new page being reloaded has no title.
1208 // See http://crbug.com/96041.
1209 EXPECT_TRUE(controller
.GetVisibleEntry()->GetTitle().empty());
1211 main_test_rfh()->PrepareForCommit();
1212 main_test_rfh()->SendNavigate(0, url1
);
1213 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1214 navigation_entry_committed_counter_
= 0;
1216 // Now the reload is committed.
1217 EXPECT_EQ(controller
.GetEntryCount(), 1);
1218 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1219 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1220 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1221 EXPECT_FALSE(controller
.GetPendingEntry());
1222 EXPECT_FALSE(controller
.CanGoBack());
1223 EXPECT_FALSE(controller
.CanGoForward());
1225 // The timestamp should have been updated.
1226 ASSERT_TRUE(controller
.GetVisibleEntry());
1227 EXPECT_GE(controller
.GetVisibleEntry()->GetTimestamp(), timestamp
);
1230 // Tests what happens when a reload navigation produces a new page.
1231 TEST_F(NavigationControllerTest
, Reload_GeneratesNewPage
) {
1232 NavigationControllerImpl
& controller
= controller_impl();
1233 TestNotificationTracker notifications
;
1234 RegisterForAllNavNotifications(¬ifications
, &controller
);
1236 const GURL
url1("http://foo1");
1237 const GURL
url2("http://foo2");
1240 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1241 main_test_rfh()->PrepareForCommit();
1242 main_test_rfh()->SendNavigate(0, url1
);
1243 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1244 navigation_entry_committed_counter_
= 0;
1246 controller
.Reload(true);
1247 EXPECT_EQ(0U, notifications
.size());
1249 main_test_rfh()->PrepareForCommitWithServerRedirect(url2
);
1250 main_test_rfh()->SendNavigate(1, url2
);
1251 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1252 navigation_entry_committed_counter_
= 0;
1254 // Now the reload is committed.
1255 EXPECT_EQ(controller
.GetEntryCount(), 2);
1256 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1257 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1258 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1259 EXPECT_FALSE(controller
.GetPendingEntry());
1260 EXPECT_TRUE(controller
.CanGoBack());
1261 EXPECT_FALSE(controller
.CanGoForward());
1264 // This test ensures that when a guest renderer reloads, the reload goes through
1265 // without ending up in the "we have a wrong process for the URL" branch in
1266 // NavigationControllerImpl::ReloadInternal.
1267 TEST_F(NavigationControllerTest
, ReloadWithGuest
) {
1268 NavigationControllerImpl
& controller
= controller_impl();
1270 const GURL
url1("http://foo1");
1272 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1273 main_test_rfh()->PrepareForCommit();
1274 main_test_rfh()->SendNavigate(0, url1
);
1275 ASSERT_TRUE(controller
.GetVisibleEntry());
1277 // Make the entry believe its RenderProcessHost is a guest.
1278 NavigationEntryImpl
* entry1
= controller
.GetVisibleEntry();
1279 reinterpret_cast<MockRenderProcessHost
*>(
1280 entry1
->site_instance()->GetProcess())->set_is_isolated_guest(true);
1283 controller
.Reload(true);
1285 // The reload is pending. Check that the NavigationEntry didn't get replaced
1286 // because of having the wrong process.
1287 EXPECT_EQ(controller
.GetEntryCount(), 1);
1288 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1289 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1291 NavigationEntryImpl
* entry2
= controller
.GetPendingEntry();
1292 EXPECT_EQ(entry1
, entry2
);
1295 #if !defined(OS_ANDROID) // http://crbug.com/157428
1296 TEST_F(NavigationControllerTest
, ReloadOriginalRequestURL
) {
1297 NavigationControllerImpl
& controller
= controller_impl();
1298 TestNotificationTracker notifications
;
1299 RegisterForAllNavNotifications(¬ifications
, &controller
);
1301 const GURL
original_url("http://foo1");
1302 const GURL
final_url("http://foo2");
1304 // Load up the original URL, but get redirected.
1306 original_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1307 EXPECT_EQ(0U, notifications
.size());
1308 main_test_rfh()->PrepareForCommitWithServerRedirect(final_url
);
1309 main_test_rfh()->SendNavigateWithOriginalRequestURL(
1310 0, final_url
, original_url
);
1311 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1312 navigation_entry_committed_counter_
= 0;
1314 // The NavigationEntry should save both the original URL and the final
1317 original_url
, controller
.GetVisibleEntry()->GetOriginalRequestURL());
1318 EXPECT_EQ(final_url
, controller
.GetVisibleEntry()->GetURL());
1320 // Reload using the original URL.
1321 controller
.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
1322 controller
.ReloadOriginalRequestURL(false);
1323 EXPECT_EQ(0U, notifications
.size());
1325 // The reload is pending. The request should point to the original URL.
1326 EXPECT_EQ(original_url
, navigated_url());
1327 EXPECT_EQ(controller
.GetEntryCount(), 1);
1328 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1329 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1330 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1331 EXPECT_TRUE(controller
.GetPendingEntry());
1332 EXPECT_FALSE(controller
.CanGoBack());
1333 EXPECT_FALSE(controller
.CanGoForward());
1335 // Make sure the title has been cleared (will be redrawn just after reload).
1336 // Avoids a stale cached title when the new page being reloaded has no title.
1337 // See http://crbug.com/96041.
1338 EXPECT_TRUE(controller
.GetVisibleEntry()->GetTitle().empty());
1340 // Send that the navigation has proceeded; say it got redirected again.
1341 main_test_rfh()->PrepareForCommitWithServerRedirect(final_url
);
1342 main_test_rfh()->SendNavigate(0, final_url
);
1343 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1344 navigation_entry_committed_counter_
= 0;
1346 // Now the reload is committed.
1347 EXPECT_EQ(controller
.GetEntryCount(), 1);
1348 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1349 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1350 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1351 EXPECT_FALSE(controller
.GetPendingEntry());
1352 EXPECT_FALSE(controller
.CanGoBack());
1353 EXPECT_FALSE(controller
.CanGoForward());
1356 #endif // !defined(OS_ANDROID)
1358 // Test that certain non-persisted NavigationEntryImpl values get reset after
1360 TEST_F(NavigationControllerTest
, ResetEntryValuesAfterCommit
) {
1361 NavigationControllerImpl
& controller
= controller_impl();
1363 // The value of "should replace entry" will be tested, but it's an error to
1364 // specify it when there are no entries. Create a simple entry to be replaced.
1365 const GURL
url0("http://foo/0");
1367 url0
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1368 main_test_rfh()->PrepareForCommit();
1369 main_test_rfh()->SendNavigate(0, url0
);
1371 // Set up the pending entry.
1372 const GURL
url1("http://foo/1");
1374 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1376 // Set up some sample values.
1377 const unsigned char* raw_data
=
1378 reinterpret_cast<const unsigned char*>("post\n\n\0data");
1379 const int length
= 11;
1380 std::vector
<unsigned char> post_data_vector(raw_data
, raw_data
+length
);
1381 scoped_refptr
<base::RefCountedBytes
> post_data
=
1382 base::RefCountedBytes::TakeVector(&post_data_vector
);
1383 GlobalRequestID
transfer_id(3, 4);
1385 // Set non-persisted values on the pending entry.
1386 NavigationEntryImpl
* pending_entry
= controller
.GetPendingEntry();
1387 pending_entry
->SetBrowserInitiatedPostData(post_data
.get());
1388 pending_entry
->set_is_renderer_initiated(true);
1389 pending_entry
->set_transferred_global_request_id(transfer_id
);
1390 pending_entry
->set_should_replace_entry(true);
1391 pending_entry
->set_should_clear_history_list(true);
1392 EXPECT_EQ(post_data
.get(), pending_entry
->GetBrowserInitiatedPostData());
1393 EXPECT_TRUE(pending_entry
->is_renderer_initiated());
1394 EXPECT_EQ(transfer_id
, pending_entry
->transferred_global_request_id());
1395 EXPECT_TRUE(pending_entry
->should_replace_entry());
1396 EXPECT_TRUE(pending_entry
->should_clear_history_list());
1398 // Fake a commit response.
1399 main_test_rfh()->PrepareForCommit();
1400 main_test_rfh()->SendNavigate(1, url1
);
1402 // Certain values that are only used for pending entries get reset after
1404 NavigationEntryImpl
* committed_entry
= controller
.GetLastCommittedEntry();
1405 EXPECT_FALSE(committed_entry
->GetBrowserInitiatedPostData());
1406 EXPECT_FALSE(committed_entry
->is_renderer_initiated());
1407 EXPECT_EQ(GlobalRequestID(-1, -1),
1408 committed_entry
->transferred_global_request_id());
1409 EXPECT_FALSE(committed_entry
->should_replace_entry());
1410 EXPECT_FALSE(committed_entry
->should_clear_history_list());
1413 // Test that Redirects are preserved after a commit.
1414 TEST_F(NavigationControllerTest
, RedirectsAreNotResetByCommit
) {
1415 NavigationControllerImpl
& controller
= controller_impl();
1416 const GURL
url1("http://foo1");
1417 const GURL
url2("http://foo2");
1419 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1421 // Set up some redirect values.
1422 std::vector
<GURL
> redirects
;
1423 redirects
.push_back(url2
);
1425 // Set redirects on the pending entry.
1426 NavigationEntryImpl
* pending_entry
= controller
.GetPendingEntry();
1427 pending_entry
->SetRedirectChain(redirects
);
1428 EXPECT_EQ(1U, pending_entry
->GetRedirectChain().size());
1429 EXPECT_EQ(url2
, pending_entry
->GetRedirectChain()[0]);
1431 // Normal navigation will preserve redirects in the committed entry.
1432 main_test_rfh()->PrepareForCommitWithServerRedirect(url2
);
1433 main_test_rfh()->SendNavigateWithRedirects(0, url1
, redirects
);
1434 NavigationEntryImpl
* committed_entry
= controller
.GetLastCommittedEntry();
1435 ASSERT_EQ(1U, committed_entry
->GetRedirectChain().size());
1436 EXPECT_EQ(url2
, committed_entry
->GetRedirectChain()[0]);
1439 // Tests what happens when we navigate back successfully
1440 TEST_F(NavigationControllerTest
, Back
) {
1441 NavigationControllerImpl
& controller
= controller_impl();
1442 TestNotificationTracker notifications
;
1443 RegisterForAllNavNotifications(¬ifications
, &controller
);
1445 const GURL
url1("http://foo1");
1446 main_test_rfh()->NavigateAndCommitRendererInitiated(0, url1
);
1447 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1448 navigation_entry_committed_counter_
= 0;
1450 const GURL
url2("http://foo2");
1451 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url2
);
1452 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1453 navigation_entry_committed_counter_
= 0;
1455 controller
.GoBack();
1456 EXPECT_EQ(0U, notifications
.size());
1458 // We should now have a pending navigation to go back.
1459 EXPECT_EQ(controller
.GetEntryCount(), 2);
1460 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1461 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1462 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1463 EXPECT_TRUE(controller
.GetPendingEntry());
1464 EXPECT_FALSE(controller
.CanGoBack());
1465 EXPECT_FALSE(controller
.CanGoToOffset(-1));
1466 EXPECT_TRUE(controller
.CanGoForward());
1467 EXPECT_TRUE(controller
.CanGoToOffset(1));
1468 EXPECT_FALSE(controller
.CanGoToOffset(2)); // Cannot go foward 2 steps.
1470 // Timestamp for entry 1 should be on or after that of entry 0.
1471 EXPECT_FALSE(controller
.GetEntryAtIndex(0)->GetTimestamp().is_null());
1472 EXPECT_GE(controller
.GetEntryAtIndex(1)->GetTimestamp(),
1473 controller
.GetEntryAtIndex(0)->GetTimestamp());
1475 main_test_rfh()->NavigateAndCommitRendererInitiated(0, url2
);
1476 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1477 navigation_entry_committed_counter_
= 0;
1479 // The back navigation completed successfully.
1480 EXPECT_EQ(controller
.GetEntryCount(), 2);
1481 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1482 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1483 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1484 EXPECT_FALSE(controller
.GetPendingEntry());
1485 EXPECT_FALSE(controller
.CanGoBack());
1486 EXPECT_FALSE(controller
.CanGoToOffset(-1));
1487 EXPECT_TRUE(controller
.CanGoForward());
1488 EXPECT_TRUE(controller
.CanGoToOffset(1));
1489 EXPECT_FALSE(controller
.CanGoToOffset(2)); // Cannot go foward 2 steps.
1491 // Timestamp for entry 0 should be on or after that of entry 1
1492 // (since we went back to it).
1493 EXPECT_GE(controller
.GetEntryAtIndex(0)->GetTimestamp(),
1494 controller
.GetEntryAtIndex(1)->GetTimestamp());
1497 // Tests what happens when a back navigation produces a new page.
1498 TEST_F(NavigationControllerTest
, Back_GeneratesNewPage
) {
1499 NavigationControllerImpl
& controller
= controller_impl();
1500 TestNotificationTracker notifications
;
1501 RegisterForAllNavNotifications(¬ifications
, &controller
);
1503 const GURL
url1("http://foo/1");
1504 const GURL
url2("http://foo/2");
1505 const GURL
url3("http://foo/3");
1508 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1509 main_test_rfh()->PrepareForCommit();
1510 main_test_rfh()->SendNavigate(0, url1
);
1511 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1512 navigation_entry_committed_counter_
= 0;
1515 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1516 main_test_rfh()->PrepareForCommit();
1517 main_test_rfh()->SendNavigate(1, url2
);
1518 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1519 navigation_entry_committed_counter_
= 0;
1521 controller
.GoBack();
1522 EXPECT_EQ(0U, notifications
.size());
1524 // We should now have a pending navigation to go back.
1525 EXPECT_EQ(controller
.GetEntryCount(), 2);
1526 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1527 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1528 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1529 EXPECT_TRUE(controller
.GetPendingEntry());
1530 EXPECT_FALSE(controller
.CanGoBack());
1531 EXPECT_TRUE(controller
.CanGoForward());
1533 main_test_rfh()->PrepareForCommitWithServerRedirect(url3
);
1534 main_test_rfh()->SendNavigate(2, url3
);
1535 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1536 navigation_entry_committed_counter_
= 0;
1538 // The back navigation resulted in a completely new navigation.
1539 // TODO(darin): perhaps this behavior will be confusing to users?
1540 EXPECT_EQ(controller
.GetEntryCount(), 3);
1541 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 2);
1542 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1543 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1544 EXPECT_FALSE(controller
.GetPendingEntry());
1545 EXPECT_TRUE(controller
.CanGoBack());
1546 EXPECT_FALSE(controller
.CanGoForward());
1549 // Receives a back message when there is a new pending navigation entry.
1550 TEST_F(NavigationControllerTest
, Back_NewPending
) {
1551 NavigationControllerImpl
& controller
= controller_impl();
1552 TestNotificationTracker notifications
;
1553 RegisterForAllNavNotifications(¬ifications
, &controller
);
1555 const GURL
kUrl1("http://foo1");
1556 const GURL
kUrl2("http://foo2");
1557 const GURL
kUrl3("http://foo3");
1559 // First navigate two places so we have some back history.
1560 main_test_rfh()->NavigateAndCommitRendererInitiated(0, kUrl1
);
1561 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1562 navigation_entry_committed_counter_
= 0;
1564 // controller.LoadURL(kUrl2, ui::PAGE_TRANSITION_TYPED);
1565 main_test_rfh()->NavigateAndCommitRendererInitiated(1, kUrl2
);
1566 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1567 navigation_entry_committed_counter_
= 0;
1569 // Now start a new pending navigation and go back before it commits.
1571 kUrl3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1572 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1573 EXPECT_EQ(kUrl3
, controller
.GetPendingEntry()->GetURL());
1574 controller
.GoBack();
1576 // The pending navigation should now be the "back" item and the new one
1578 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
1579 EXPECT_EQ(kUrl1
, controller
.GetPendingEntry()->GetURL());
1582 // Receives a back message when there is a different renavigation already
1584 TEST_F(NavigationControllerTest
, Back_OtherBackPending
) {
1585 NavigationControllerImpl
& controller
= controller_impl();
1586 const GURL
kUrl1("http://foo/1");
1587 const GURL
kUrl2("http://foo/2");
1588 const GURL
kUrl3("http://foo/3");
1590 // First navigate three places so we have some back history.
1591 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1
, true);
1592 main_test_rfh()->PrepareForCommit();
1593 main_test_rfh()->SendNavigate(0, kUrl1
);
1594 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, true);
1595 main_test_rfh()->PrepareForCommit();
1596 main_test_rfh()->SendNavigate(1, kUrl2
);
1597 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl3
, true);
1598 main_test_rfh()->PrepareForCommit();
1599 main_test_rfh()->SendNavigate(2, kUrl3
);
1601 // With nothing pending, say we get a renderer back navigation request to the
1603 controller
.GoToOffset(-1);
1604 main_test_rfh()->PrepareForCommit();
1605 main_test_rfh()->SendNavigate(1, kUrl2
);
1607 // We know all the entries have the same site instance, so we can just grab
1608 // a random one for looking up other entries.
1609 SiteInstance
* site_instance
=
1610 controller
.GetLastCommittedEntry()->site_instance();
1612 // That second URL should be the last committed and it should have gotten the
1614 EXPECT_EQ(kUrl2
, controller
.GetEntryWithPageID(site_instance
, 1)->GetURL());
1615 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1616 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1618 // Now go forward to the last item again and say it was committed.
1619 controller
.GoForward();
1620 main_test_rfh()->PrepareForCommit();
1621 main_test_rfh()->SendNavigate(2, kUrl3
);
1623 // Now start going back one to the second page. It will be pending.
1624 controller
.GoBack();
1625 EXPECT_EQ(1, controller
.GetPendingEntryIndex());
1626 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1628 // Now have the renderer request a navigation back to the first page. This
1629 // will not match the pending one.
1630 controller
.GoToOffset(-2);
1631 main_test_rfh()->PrepareForCommit();
1632 main_test_rfh()->SendNavigate(0, kUrl1
);
1634 // The committed navigation should clear the pending entry.
1635 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1637 // But the navigated entry should be the last committed.
1638 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1639 EXPECT_EQ(kUrl1
, controller
.GetLastCommittedEntry()->GetURL());
1642 // Tests what happens when we navigate forward successfully.
1643 TEST_F(NavigationControllerTest
, Forward
) {
1644 NavigationControllerImpl
& controller
= controller_impl();
1645 TestNotificationTracker notifications
;
1646 RegisterForAllNavNotifications(¬ifications
, &controller
);
1648 const GURL
url1("http://foo1");
1649 const GURL
url2("http://foo2");
1651 main_test_rfh()->SendRendererInitiatedNavigationRequest(url1
, true);
1652 main_test_rfh()->PrepareForCommit();
1653 main_test_rfh()->SendNavigate(0, url1
);
1654 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1655 navigation_entry_committed_counter_
= 0;
1657 main_test_rfh()->SendRendererInitiatedNavigationRequest(url2
, true);
1658 main_test_rfh()->PrepareForCommit();
1659 main_test_rfh()->SendNavigate(1, url2
);
1660 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1661 navigation_entry_committed_counter_
= 0;
1663 controller
.GoBack();
1664 main_test_rfh()->PrepareForCommit();
1665 main_test_rfh()->SendNavigate(0, url1
);
1666 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1667 navigation_entry_committed_counter_
= 0;
1669 controller
.GoForward();
1671 // We should now have a pending navigation to go forward.
1672 EXPECT_EQ(controller
.GetEntryCount(), 2);
1673 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1674 EXPECT_EQ(controller
.GetPendingEntryIndex(), 1);
1675 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1676 EXPECT_TRUE(controller
.GetPendingEntry());
1677 EXPECT_TRUE(controller
.CanGoBack());
1678 EXPECT_TRUE(controller
.CanGoToOffset(-1));
1679 EXPECT_FALSE(controller
.CanGoToOffset(-2)); // Cannot go back 2 steps.
1680 EXPECT_FALSE(controller
.CanGoForward());
1681 EXPECT_FALSE(controller
.CanGoToOffset(1));
1683 // Timestamp for entry 0 should be on or after that of entry 1
1684 // (since we went back to it).
1685 EXPECT_FALSE(controller
.GetEntryAtIndex(0)->GetTimestamp().is_null());
1686 EXPECT_GE(controller
.GetEntryAtIndex(0)->GetTimestamp(),
1687 controller
.GetEntryAtIndex(1)->GetTimestamp());
1689 main_test_rfh()->PrepareForCommit();
1690 main_test_rfh()->SendNavigate(1, url2
);
1691 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1692 navigation_entry_committed_counter_
= 0;
1694 // The forward navigation completed successfully.
1695 EXPECT_EQ(controller
.GetEntryCount(), 2);
1696 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1697 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1698 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1699 EXPECT_FALSE(controller
.GetPendingEntry());
1700 EXPECT_TRUE(controller
.CanGoBack());
1701 EXPECT_TRUE(controller
.CanGoToOffset(-1));
1702 EXPECT_FALSE(controller
.CanGoToOffset(-2)); // Cannot go back 2 steps.
1703 EXPECT_FALSE(controller
.CanGoForward());
1704 EXPECT_FALSE(controller
.CanGoToOffset(1));
1706 // Timestamp for entry 1 should be on or after that of entry 0
1707 // (since we went forward to it).
1708 EXPECT_GE(controller
.GetEntryAtIndex(1)->GetTimestamp(),
1709 controller
.GetEntryAtIndex(0)->GetTimestamp());
1712 // Tests what happens when a forward navigation produces a new page.
1713 TEST_F(NavigationControllerTest
, Forward_GeneratesNewPage
) {
1714 NavigationControllerImpl
& controller
= controller_impl();
1715 TestNotificationTracker notifications
;
1716 RegisterForAllNavNotifications(¬ifications
, &controller
);
1718 const GURL
url1("http://foo1");
1719 const GURL
url2("http://foo2");
1720 const GURL
url3("http://foo3");
1722 main_test_rfh()->SendRendererInitiatedNavigationRequest(url1
, true);
1723 main_test_rfh()->PrepareForCommit();
1724 main_test_rfh()->SendNavigate(0, url1
);
1725 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1726 navigation_entry_committed_counter_
= 0;
1727 main_test_rfh()->SendRendererInitiatedNavigationRequest(url2
, true);
1728 main_test_rfh()->PrepareForCommit();
1729 main_test_rfh()->SendNavigate(1, url2
);
1730 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1731 navigation_entry_committed_counter_
= 0;
1733 controller
.GoBack();
1734 main_test_rfh()->PrepareForCommit();
1735 main_test_rfh()->SendNavigate(0, url1
);
1736 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1737 navigation_entry_committed_counter_
= 0;
1739 controller
.GoForward();
1740 EXPECT_EQ(0U, notifications
.size());
1742 // Should now have a pending navigation to go forward.
1743 EXPECT_EQ(controller
.GetEntryCount(), 2);
1744 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1745 EXPECT_EQ(controller
.GetPendingEntryIndex(), 1);
1746 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1747 EXPECT_TRUE(controller
.GetPendingEntry());
1748 EXPECT_TRUE(controller
.CanGoBack());
1749 EXPECT_FALSE(controller
.CanGoForward());
1751 main_test_rfh()->PrepareForCommit();
1752 main_test_rfh()->SendNavigate(2, url3
);
1753 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1754 navigation_entry_committed_counter_
= 0;
1755 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_LIST_PRUNED
));
1757 EXPECT_EQ(controller
.GetEntryCount(), 2);
1758 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1759 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1760 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1761 EXPECT_FALSE(controller
.GetPendingEntry());
1762 EXPECT_TRUE(controller
.CanGoBack());
1763 EXPECT_FALSE(controller
.CanGoForward());
1766 // Two consecutive navigations for the same URL entered in should be considered
1767 // as SAME_PAGE navigation even when we are redirected to some other page.
1768 TEST_F(NavigationControllerTest
, Redirect
) {
1769 NavigationControllerImpl
& controller
= controller_impl();
1770 TestNotificationTracker notifications
;
1771 RegisterForAllNavNotifications(¬ifications
, &controller
);
1773 const GURL
url1("http://foo1");
1774 const GURL
url2("http://foo2"); // Redirection target
1778 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1780 EXPECT_EQ(0U, notifications
.size());
1782 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
1785 params
.transition
= ui::PAGE_TRANSITION_SERVER_REDIRECT
;
1786 params
.redirects
.push_back(GURL("http://foo1"));
1787 params
.redirects
.push_back(GURL("http://foo2"));
1788 params
.should_update_history
= false;
1789 params
.gesture
= NavigationGestureAuto
;
1790 params
.is_post
= false;
1791 params
.page_state
= PageState::CreateFromURL(url2
);
1793 LoadCommittedDetails details
;
1795 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1797 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1798 navigation_entry_committed_counter_
= 0;
1802 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1804 EXPECT_TRUE(controller
.GetPendingEntry());
1805 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1806 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
1807 EXPECT_EQ(0U, notifications
.size());
1808 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1810 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1811 navigation_entry_committed_counter_
= 0;
1813 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_SAME_PAGE
);
1814 EXPECT_EQ(controller
.GetEntryCount(), 1);
1815 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1816 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1817 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1818 EXPECT_FALSE(controller
.GetPendingEntry());
1819 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
1821 EXPECT_FALSE(controller
.CanGoBack());
1822 EXPECT_FALSE(controller
.CanGoForward());
1825 // Similar to Redirect above, but the first URL is requested by POST,
1826 // the second URL is requested by GET. NavigationEntry::has_post_data_
1827 // must be cleared. http://crbug.com/21245
1828 TEST_F(NavigationControllerTest
, PostThenRedirect
) {
1829 NavigationControllerImpl
& controller
= controller_impl();
1830 TestNotificationTracker notifications
;
1831 RegisterForAllNavNotifications(¬ifications
, &controller
);
1833 const GURL
url1("http://foo1");
1834 const GURL
url2("http://foo2"); // Redirection target
1836 // First request as POST.
1838 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1839 controller
.GetVisibleEntry()->SetHasPostData(true);
1841 EXPECT_EQ(0U, notifications
.size());
1843 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
1846 params
.transition
= ui::PAGE_TRANSITION_SERVER_REDIRECT
;
1847 params
.redirects
.push_back(GURL("http://foo1"));
1848 params
.redirects
.push_back(GURL("http://foo2"));
1849 params
.should_update_history
= false;
1850 params
.gesture
= NavigationGestureAuto
;
1851 params
.is_post
= true;
1852 params
.page_state
= PageState::CreateFromURL(url2
);
1854 LoadCommittedDetails details
;
1856 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1858 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1859 navigation_entry_committed_counter_
= 0;
1863 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1865 EXPECT_TRUE(controller
.GetPendingEntry());
1866 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1867 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
1869 params
.is_post
= false;
1871 EXPECT_EQ(0U, notifications
.size());
1872 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1874 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1875 navigation_entry_committed_counter_
= 0;
1877 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_SAME_PAGE
);
1878 EXPECT_EQ(controller
.GetEntryCount(), 1);
1879 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1880 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1881 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1882 EXPECT_FALSE(controller
.GetPendingEntry());
1883 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
1884 EXPECT_FALSE(controller
.GetVisibleEntry()->GetHasPostData());
1886 EXPECT_FALSE(controller
.CanGoBack());
1887 EXPECT_FALSE(controller
.CanGoForward());
1890 // A redirect right off the bat should be a NEW_PAGE.
1891 TEST_F(NavigationControllerTest
, ImmediateRedirect
) {
1892 NavigationControllerImpl
& controller
= controller_impl();
1893 TestNotificationTracker notifications
;
1894 RegisterForAllNavNotifications(¬ifications
, &controller
);
1896 const GURL
url1("http://foo1");
1897 const GURL
url2("http://foo2"); // Redirection target
1901 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1903 EXPECT_TRUE(controller
.GetPendingEntry());
1904 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1905 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
1907 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
1910 params
.transition
= ui::PAGE_TRANSITION_SERVER_REDIRECT
;
1911 params
.redirects
.push_back(GURL("http://foo1"));
1912 params
.redirects
.push_back(GURL("http://foo2"));
1913 params
.should_update_history
= false;
1914 params
.gesture
= NavigationGestureAuto
;
1915 params
.is_post
= false;
1916 params
.page_state
= PageState::CreateFromURL(url2
);
1918 LoadCommittedDetails details
;
1920 EXPECT_EQ(0U, notifications
.size());
1921 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1923 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1924 navigation_entry_committed_counter_
= 0;
1926 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_NEW_PAGE
);
1927 EXPECT_EQ(controller
.GetEntryCount(), 1);
1928 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1929 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1930 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1931 EXPECT_FALSE(controller
.GetPendingEntry());
1932 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
1934 EXPECT_FALSE(controller
.CanGoBack());
1935 EXPECT_FALSE(controller
.CanGoForward());
1938 // Tests navigation via link click within a subframe. A new navigation entry
1939 // should be created.
1940 TEST_F(NavigationControllerTest
, NewSubframe
) {
1941 NavigationControllerImpl
& controller
= controller_impl();
1942 TestNotificationTracker notifications
;
1943 RegisterForAllNavNotifications(¬ifications
, &controller
);
1945 const GURL
url1("http://foo1");
1946 main_test_rfh()->NavigateAndCommitRendererInitiated(0, url1
);
1947 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1948 navigation_entry_committed_counter_
= 0;
1950 const GURL
url2("http://foo2");
1951 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
1954 params
.transition
= ui::PAGE_TRANSITION_MANUAL_SUBFRAME
;
1955 params
.should_update_history
= false;
1956 params
.gesture
= NavigationGestureUser
;
1957 params
.is_post
= false;
1958 params
.page_state
= PageState::CreateFromURL(url2
);
1960 LoadCommittedDetails details
;
1961 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
1963 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1964 navigation_entry_committed_counter_
= 0;
1965 EXPECT_EQ(url1
, details
.previous_url
);
1966 EXPECT_FALSE(details
.is_in_page
);
1967 EXPECT_FALSE(details
.is_main_frame
);
1969 // The new entry should be appended.
1970 EXPECT_EQ(2, controller
.GetEntryCount());
1972 // New entry should refer to the new page, but the old URL (entries only
1973 // reflect the toplevel URL).
1974 EXPECT_EQ(url1
, details
.entry
->GetURL());
1975 EXPECT_EQ(params
.page_id
, details
.entry
->GetPageID());
1978 // Auto subframes are ones the page loads automatically like ads. They should
1979 // not create new navigation entries.
1980 // TODO(creis): Test cross-site and nested iframes.
1981 // TODO(creis): Test updating entries for history auto subframe navigations.
1982 TEST_F(NavigationControllerTest
, AutoSubframe
) {
1983 NavigationControllerImpl
& controller
= controller_impl();
1984 TestNotificationTracker notifications
;
1985 RegisterForAllNavNotifications(¬ifications
, &controller
);
1987 const GURL
url1("http://foo/1");
1988 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url1
);
1989 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1990 navigation_entry_committed_counter_
= 0;
1992 // Add a subframe and navigate it.
1993 main_test_rfh()->OnCreateChildFrame(MSG_ROUTING_NONE
, std::string(),
1994 SandboxFlags::NONE
);
1995 RenderFrameHostImpl
* subframe
=
1996 contents()->GetFrameTree()->root()->child_at(0)->current_frame_host();
1997 const GURL
url2("http://foo/2");
1999 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2002 params
.transition
= ui::PAGE_TRANSITION_AUTO_SUBFRAME
;
2003 params
.should_update_history
= false;
2004 params
.gesture
= NavigationGestureUser
;
2005 params
.is_post
= false;
2006 params
.page_state
= PageState::CreateFromURL(url2
);
2008 // Navigating should do nothing.
2009 LoadCommittedDetails details
;
2010 EXPECT_FALSE(controller
.RendererDidNavigate(subframe
, params
, &details
));
2011 EXPECT_EQ(0U, notifications
.size());
2014 // There should still be only one entry.
2015 EXPECT_EQ(1, controller
.GetEntryCount());
2016 NavigationEntryImpl
* entry
= controller
.GetLastCommittedEntry();
2017 EXPECT_EQ(url1
, entry
->GetURL());
2018 EXPECT_EQ(1, entry
->GetPageID());
2019 FrameNavigationEntry
* root_entry
= entry
->root_node()->frame_entry
.get();
2020 EXPECT_EQ(url1
, root_entry
->url());
2022 // Verify subframe entries if we're in --site-per-process mode.
2023 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
2024 switches::kSitePerProcess
)) {
2025 // The entry should now have a subframe FrameNavigationEntry.
2026 ASSERT_EQ(1U, entry
->root_node()->children
.size());
2027 FrameNavigationEntry
* frame_entry
=
2028 entry
->root_node()->children
[0]->frame_entry
.get();
2029 EXPECT_EQ(url2
, frame_entry
->url());
2031 // There are no subframe FrameNavigationEntries by default.
2032 EXPECT_EQ(0U, entry
->root_node()->children
.size());
2035 // Add a second subframe and navigate.
2036 main_test_rfh()->OnCreateChildFrame(MSG_ROUTING_NONE
, std::string(),
2037 SandboxFlags::NONE
);
2038 RenderFrameHostImpl
* subframe2
=
2039 contents()->GetFrameTree()->root()->child_at(1)->current_frame_host();
2040 const GURL
url3("http://foo/3");
2042 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2045 params
.transition
= ui::PAGE_TRANSITION_AUTO_SUBFRAME
;
2046 params
.should_update_history
= false;
2047 params
.gesture
= NavigationGestureUser
;
2048 params
.is_post
= false;
2049 params
.page_state
= PageState::CreateFromURL(url3
);
2051 // Navigating should do nothing.
2052 LoadCommittedDetails details
;
2053 EXPECT_FALSE(controller
.RendererDidNavigate(subframe2
, params
, &details
));
2054 EXPECT_EQ(0U, notifications
.size());
2057 // There should still be only one entry, mostly unchanged.
2058 EXPECT_EQ(1, controller
.GetEntryCount());
2059 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
2060 EXPECT_EQ(url1
, entry
->GetURL());
2061 EXPECT_EQ(1, entry
->GetPageID());
2062 EXPECT_EQ(root_entry
, entry
->root_node()->frame_entry
.get());
2063 EXPECT_EQ(url1
, root_entry
->url());
2065 // Verify subframe entries if we're in --site-per-process mode.
2066 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
2067 switches::kSitePerProcess
)) {
2068 // The entry should now have 2 subframe FrameNavigationEntries.
2069 ASSERT_EQ(2U, entry
->root_node()->children
.size());
2070 FrameNavigationEntry
* new_frame_entry
=
2071 entry
->root_node()->children
[1]->frame_entry
.get();
2072 EXPECT_EQ(url3
, new_frame_entry
->url());
2074 // There are no subframe FrameNavigationEntries by default.
2075 EXPECT_EQ(0U, entry
->root_node()->children
.size());
2079 // Tests navigation and then going back to a subframe navigation.
2080 TEST_F(NavigationControllerTest
, BackSubframe
) {
2081 NavigationControllerImpl
& controller
= controller_impl();
2082 TestNotificationTracker notifications
;
2083 RegisterForAllNavNotifications(¬ifications
, &controller
);
2086 const GURL
url1("http://foo1");
2087 main_test_rfh()->NavigateAndCommitRendererInitiated(0, url1
);
2088 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2089 navigation_entry_committed_counter_
= 0;
2091 // First manual subframe navigation.
2092 const GURL
url2("http://foo2");
2093 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2096 params
.transition
= ui::PAGE_TRANSITION_MANUAL_SUBFRAME
;
2097 params
.should_update_history
= false;
2098 params
.gesture
= NavigationGestureUser
;
2099 params
.is_post
= false;
2100 params
.page_state
= PageState::CreateFromURL(url2
);
2102 // This should generate a new entry.
2103 LoadCommittedDetails details
;
2104 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2106 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2107 navigation_entry_committed_counter_
= 0;
2108 EXPECT_EQ(2, controller
.GetEntryCount());
2110 // Second manual subframe navigation should also make a new entry.
2111 const GURL
url3("http://foo3");
2114 params
.transition
= ui::PAGE_TRANSITION_MANUAL_SUBFRAME
;
2115 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2117 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2118 navigation_entry_committed_counter_
= 0;
2119 EXPECT_EQ(3, controller
.GetEntryCount());
2120 EXPECT_EQ(2, controller
.GetCurrentEntryIndex());
2123 controller
.GoBack();
2126 params
.transition
= ui::PAGE_TRANSITION_AUTO_SUBFRAME
;
2127 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2129 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2130 navigation_entry_committed_counter_
= 0;
2131 EXPECT_EQ(3, controller
.GetEntryCount());
2132 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
2133 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
2134 EXPECT_FALSE(controller
.GetPendingEntry());
2136 // Go back one more.
2137 controller
.GoBack();
2140 params
.transition
= ui::PAGE_TRANSITION_AUTO_SUBFRAME
;
2141 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2143 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2144 navigation_entry_committed_counter_
= 0;
2145 EXPECT_EQ(3, controller
.GetEntryCount());
2146 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
2147 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
2148 EXPECT_FALSE(controller
.GetPendingEntry());
2151 TEST_F(NavigationControllerTest
, LinkClick
) {
2152 NavigationControllerImpl
& controller
= controller_impl();
2153 TestNotificationTracker notifications
;
2154 RegisterForAllNavNotifications(¬ifications
, &controller
);
2156 const GURL
url1("http://foo1");
2157 const GURL
url2("http://foo2");
2159 main_test_rfh()->NavigateAndCommitRendererInitiated(0, url1
);
2160 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2161 navigation_entry_committed_counter_
= 0;
2163 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url2
);
2164 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2165 navigation_entry_committed_counter_
= 0;
2167 // Should not have produced a new session history entry.
2168 EXPECT_EQ(controller
.GetEntryCount(), 2);
2169 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
2170 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
2171 EXPECT_TRUE(controller
.GetLastCommittedEntry());
2172 EXPECT_FALSE(controller
.GetPendingEntry());
2173 EXPECT_TRUE(controller
.CanGoBack());
2174 EXPECT_FALSE(controller
.CanGoForward());
2177 TEST_F(NavigationControllerTest
, InPage
) {
2178 NavigationControllerImpl
& controller
= controller_impl();
2179 TestNotificationTracker notifications
;
2180 RegisterForAllNavNotifications(¬ifications
, &controller
);
2183 const GURL
url1("http://foo");
2184 main_test_rfh()->NavigateAndCommitRendererInitiated(0, url1
);
2185 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2186 navigation_entry_committed_counter_
= 0;
2188 // Ensure main page navigation to same url respects the was_within_same_page
2189 // hint provided in the params.
2190 FrameHostMsg_DidCommitProvisionalLoad_Params self_params
;
2191 self_params
.page_id
= 0;
2192 self_params
.url
= url1
;
2193 self_params
.transition
= ui::PAGE_TRANSITION_LINK
;
2194 self_params
.should_update_history
= false;
2195 self_params
.gesture
= NavigationGestureUser
;
2196 self_params
.is_post
= false;
2197 self_params
.page_state
= PageState::CreateFromURL(url1
);
2198 self_params
.was_within_same_page
= true;
2200 LoadCommittedDetails details
;
2201 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), self_params
,
2203 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2204 navigation_entry_committed_counter_
= 0;
2205 EXPECT_TRUE(details
.is_in_page
);
2206 EXPECT_TRUE(details
.did_replace_entry
);
2207 EXPECT_EQ(1, controller
.GetEntryCount());
2209 // Fragment navigation to a new page_id.
2210 const GURL
url2("http://foo#a");
2211 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2214 params
.transition
= ui::PAGE_TRANSITION_LINK
;
2215 params
.should_update_history
= false;
2216 params
.gesture
= NavigationGestureUser
;
2217 params
.is_post
= false;
2218 params
.page_state
= PageState::CreateFromURL(url2
);
2219 params
.was_within_same_page
= true;
2221 // This should generate a new entry.
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_FALSE(details
.did_replace_entry
);
2228 EXPECT_EQ(2, controller
.GetEntryCount());
2231 FrameHostMsg_DidCommitProvisionalLoad_Params
back_params(params
);
2232 controller
.GoBack();
2233 back_params
.url
= url1
;
2234 back_params
.page_id
= 0;
2235 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), back_params
,
2237 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2238 navigation_entry_committed_counter_
= 0;
2239 EXPECT_TRUE(details
.is_in_page
);
2240 EXPECT_EQ(2, controller
.GetEntryCount());
2241 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
2242 EXPECT_EQ(back_params
.url
, controller
.GetVisibleEntry()->GetURL());
2245 FrameHostMsg_DidCommitProvisionalLoad_Params
forward_params(params
);
2246 controller
.GoForward();
2247 forward_params
.url
= url2
;
2248 forward_params
.page_id
= 1;
2249 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), forward_params
,
2251 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2252 navigation_entry_committed_counter_
= 0;
2253 EXPECT_TRUE(details
.is_in_page
);
2254 EXPECT_EQ(2, controller
.GetEntryCount());
2255 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
2256 EXPECT_EQ(forward_params
.url
,
2257 controller
.GetVisibleEntry()->GetURL());
2259 // Now go back and forward again. This is to work around a bug where we would
2260 // compare the incoming URL with the last committed entry rather than the
2261 // one identified by an existing page ID. This would result in the second URL
2262 // losing the reference fragment when you navigate away from it and then back.
2263 controller
.GoBack();
2264 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), back_params
,
2266 controller
.GoForward();
2267 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), forward_params
,
2269 EXPECT_EQ(forward_params
.url
,
2270 controller
.GetVisibleEntry()->GetURL());
2272 // Finally, navigate to an unrelated URL to make sure in_page is not sticky.
2273 const GURL
url3("http://bar");
2276 navigation_entry_committed_counter_
= 0;
2277 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2279 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2280 navigation_entry_committed_counter_
= 0;
2281 EXPECT_FALSE(details
.is_in_page
);
2282 EXPECT_EQ(3, controller
.GetEntryCount());
2283 EXPECT_EQ(2, controller
.GetCurrentEntryIndex());
2286 TEST_F(NavigationControllerTest
, InPage_Replace
) {
2287 NavigationControllerImpl
& controller
= controller_impl();
2288 TestNotificationTracker notifications
;
2289 RegisterForAllNavNotifications(¬ifications
, &controller
);
2292 const GURL
url1("http://foo");
2293 main_test_rfh()->NavigateAndCommitRendererInitiated(0, url1
);
2294 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2295 navigation_entry_committed_counter_
= 0;
2297 // First navigation.
2298 const GURL
url2("http://foo#a");
2299 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2300 params
.page_id
= 0; // Same page_id
2302 params
.transition
= ui::PAGE_TRANSITION_LINK
;
2303 params
.should_update_history
= false;
2304 params
.gesture
= NavigationGestureUser
;
2305 params
.is_post
= false;
2306 params
.page_state
= PageState::CreateFromURL(url2
);
2307 params
.was_within_same_page
= true;
2309 // This should NOT generate a new entry, nor prune the list.
2310 LoadCommittedDetails details
;
2311 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2313 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2314 navigation_entry_committed_counter_
= 0;
2315 EXPECT_TRUE(details
.is_in_page
);
2316 EXPECT_TRUE(details
.did_replace_entry
);
2317 EXPECT_EQ(1, controller
.GetEntryCount());
2320 // Tests for http://crbug.com/40395
2323 // window.location.replace("#a");
2324 // window.location='http://foo3/';
2326 TEST_F(NavigationControllerTest
, ClientRedirectAfterInPageNavigation
) {
2327 NavigationControllerImpl
& controller
= controller_impl();
2328 TestNotificationTracker notifications
;
2329 RegisterForAllNavNotifications(¬ifications
, &controller
);
2331 // Load an initial page.
2333 const GURL
url("http://foo/");
2334 main_test_rfh()->NavigateAndCommitRendererInitiated(0, url
);
2335 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2336 navigation_entry_committed_counter_
= 0;
2339 // Navigate to a new page.
2341 const GURL
url("http://foo2/");
2342 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url
);
2343 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2344 navigation_entry_committed_counter_
= 0;
2347 // Navigate within the page.
2349 const GURL
url("http://foo2/#a");
2350 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2351 params
.page_id
= 1; // Same page_id
2353 params
.transition
= ui::PAGE_TRANSITION_LINK
;
2354 params
.redirects
.push_back(url
);
2355 params
.should_update_history
= true;
2356 params
.gesture
= NavigationGestureUnknown
;
2357 params
.is_post
= false;
2358 params
.page_state
= PageState::CreateFromURL(url
);
2359 params
.was_within_same_page
= true;
2361 // This should NOT generate a new entry, nor prune the list.
2362 LoadCommittedDetails details
;
2363 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2365 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2366 navigation_entry_committed_counter_
= 0;
2367 EXPECT_TRUE(details
.is_in_page
);
2368 EXPECT_TRUE(details
.did_replace_entry
);
2369 EXPECT_EQ(2, controller
.GetEntryCount());
2372 // Perform a client redirect to a new page.
2374 const GURL
url("http://foo3/");
2375 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2376 params
.page_id
= 2; // New page_id
2378 params
.transition
= ui::PAGE_TRANSITION_CLIENT_REDIRECT
;
2379 params
.redirects
.push_back(GURL("http://foo2/#a"));
2380 params
.redirects
.push_back(url
);
2381 params
.should_update_history
= true;
2382 params
.gesture
= NavigationGestureUnknown
;
2383 params
.is_post
= false;
2384 params
.page_state
= PageState::CreateFromURL(url
);
2386 // This SHOULD generate a new entry.
2387 LoadCommittedDetails details
;
2388 EXPECT_TRUE(controller
.RendererDidNavigate(main_test_rfh(), params
,
2390 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2391 navigation_entry_committed_counter_
= 0;
2392 EXPECT_FALSE(details
.is_in_page
);
2393 EXPECT_EQ(3, controller
.GetEntryCount());
2396 // Verify that BACK brings us back to http://foo2/.
2398 const GURL
url("http://foo2/");
2399 controller
.GoBack();
2400 main_test_rfh()->PrepareForCommit();
2401 main_test_rfh()->SendNavigate(1, url
);
2402 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2403 navigation_entry_committed_counter_
= 0;
2404 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
2408 TEST_F(NavigationControllerTest
, PushStateWithoutPreviousEntry
)
2410 ASSERT_FALSE(controller_impl().GetLastCommittedEntry());
2411 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2412 GURL
url("http://foo");
2415 params
.page_state
= PageState::CreateFromURL(url
);
2416 params
.was_within_same_page
= true;
2417 main_test_rfh()->SendRendererInitiatedNavigationRequest(url
, false);
2418 main_test_rfh()->PrepareForCommit();
2419 contents()->GetMainFrame()->SendNavigateWithParams(¶ms
);
2420 // We pass if we don't crash.
2423 // NotificationObserver implementation used in verifying we've received the
2424 // NOTIFICATION_NAV_LIST_PRUNED method.
2425 class PrunedListener
: public NotificationObserver
{
2427 explicit PrunedListener(NavigationControllerImpl
* controller
)
2428 : notification_count_(0) {
2429 registrar_
.Add(this, NOTIFICATION_NAV_LIST_PRUNED
,
2430 Source
<NavigationController
>(controller
));
2433 void Observe(int type
,
2434 const NotificationSource
& source
,
2435 const NotificationDetails
& details
) override
{
2436 if (type
== NOTIFICATION_NAV_LIST_PRUNED
) {
2437 notification_count_
++;
2438 details_
= *(Details
<PrunedDetails
>(details
).ptr());
2442 // Number of times NAV_LIST_PRUNED has been observed.
2443 int notification_count_
;
2445 // Details from the last NAV_LIST_PRUNED.
2446 PrunedDetails details_
;
2449 NotificationRegistrar registrar_
;
2451 DISALLOW_COPY_AND_ASSIGN(PrunedListener
);
2454 // Tests that we limit the number of navigation entries created correctly.
2455 TEST_F(NavigationControllerTest
, EnforceMaxNavigationCount
) {
2456 NavigationControllerImpl
& controller
= controller_impl();
2457 size_t original_count
= NavigationControllerImpl::max_entry_count();
2458 const int kMaxEntryCount
= 5;
2460 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
2463 // Load up to the max count, all entries should be there.
2464 for (url_index
= 0; url_index
< kMaxEntryCount
; url_index
++) {
2465 GURL
url(base::StringPrintf("http://www.a.com/%d", url_index
));
2467 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2468 main_test_rfh()->PrepareForCommit();
2469 main_test_rfh()->SendNavigate(url_index
, url
);
2472 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
2474 // Created a PrunedListener to observe prune notifications.
2475 PrunedListener
listener(&controller
);
2477 // Navigate some more.
2478 GURL
url(base::StringPrintf("http://www.a.com/%d", url_index
));
2480 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2481 main_test_rfh()->PrepareForCommit();
2482 main_test_rfh()->SendNavigate(url_index
, url
);
2485 // We should have got a pruned navigation.
2486 EXPECT_EQ(1, listener
.notification_count_
);
2487 EXPECT_TRUE(listener
.details_
.from_front
);
2488 EXPECT_EQ(1, listener
.details_
.count
);
2490 // We expect http://www.a.com/0 to be gone.
2491 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
2492 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(),
2493 GURL("http:////www.a.com/1"));
2495 // More navigations.
2496 for (int i
= 0; i
< 3; i
++) {
2497 url
= GURL(base::StringPrintf("http:////www.a.com/%d", url_index
));
2499 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2500 main_test_rfh()->PrepareForCommit();
2501 main_test_rfh()->SendNavigate(url_index
, url
);
2504 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
2505 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(),
2506 GURL("http:////www.a.com/4"));
2508 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
2511 // Tests that we can do a restore and navigate to the restored entries and
2512 // everything is updated properly. This can be tricky since there is no
2513 // SiteInstance for the entries created initially.
2514 TEST_F(NavigationControllerTest
, RestoreNavigate
) {
2515 // Create a NavigationController with a restored set of tabs.
2516 GURL
url("http://foo");
2517 std::vector
<NavigationEntry
*> entries
;
2518 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
2519 url
, Referrer(), ui::PAGE_TRANSITION_RELOAD
, false, std::string(),
2521 entry
->SetPageID(0);
2522 entry
->SetTitle(base::ASCIIToUTF16("Title"));
2523 entry
->SetPageState(PageState::CreateFromEncodedData("state"));
2524 const base::Time timestamp
= base::Time::Now();
2525 entry
->SetTimestamp(timestamp
);
2526 entries
.push_back(entry
);
2527 scoped_ptr
<WebContentsImpl
> our_contents(static_cast<WebContentsImpl
*>(
2528 WebContents::Create(WebContents::CreateParams(browser_context()))));
2529 NavigationControllerImpl
& our_controller
= our_contents
->GetController();
2530 our_controller
.Restore(
2532 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2534 ASSERT_EQ(0u, entries
.size());
2536 // Before navigating to the restored entry, it should have a restore_type
2537 // and no SiteInstance.
2538 ASSERT_EQ(1, our_controller
.GetEntryCount());
2539 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2540 our_controller
.GetEntryAtIndex(0)->restore_type());
2541 EXPECT_FALSE(our_controller
.GetEntryAtIndex(0)->site_instance());
2543 // After navigating, we should have one entry, and it should be "pending".
2544 // It should now have a SiteInstance and no restore_type.
2545 our_controller
.GoToIndex(0);
2546 EXPECT_EQ(1, our_controller
.GetEntryCount());
2547 EXPECT_EQ(our_controller
.GetEntryAtIndex(0),
2548 our_controller
.GetPendingEntry());
2549 EXPECT_EQ(0, our_controller
.GetEntryAtIndex(0)->GetPageID());
2550 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2551 our_controller
.GetEntryAtIndex(0)->restore_type());
2552 EXPECT_TRUE(our_controller
.GetEntryAtIndex(0)->site_instance());
2554 // Timestamp should remain the same before the navigation finishes.
2555 EXPECT_EQ(timestamp
, our_controller
.GetEntryAtIndex(0)->GetTimestamp());
2557 // Say we navigated to that entry.
2558 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2561 params
.transition
= ui::PAGE_TRANSITION_LINK
;
2562 params
.should_update_history
= false;
2563 params
.gesture
= NavigationGestureUser
;
2564 params
.is_post
= false;
2565 params
.page_state
= PageState::CreateFromURL(url
);
2566 LoadCommittedDetails details
;
2567 our_controller
.RendererDidNavigate(our_contents
->GetMainFrame(), params
,
2570 // There should be no longer any pending entry and one committed one. This
2571 // means that we were able to locate the entry, assign its site instance, and
2572 // commit it properly.
2573 EXPECT_EQ(1, our_controller
.GetEntryCount());
2574 EXPECT_EQ(0, our_controller
.GetLastCommittedEntryIndex());
2575 EXPECT_FALSE(our_controller
.GetPendingEntry());
2578 our_controller
.GetLastCommittedEntry()->site_instance()->GetSiteURL());
2579 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2580 our_controller
.GetEntryAtIndex(0)->restore_type());
2582 // Timestamp should have been updated.
2583 EXPECT_GE(our_controller
.GetEntryAtIndex(0)->GetTimestamp(), timestamp
);
2586 // Tests that we can still navigate to a restored entry after a different
2587 // navigation fails and clears the pending entry. http://crbug.com/90085
2588 TEST_F(NavigationControllerTest
, RestoreNavigateAfterFailure
) {
2589 // Create a NavigationController with a restored set of tabs.
2590 GURL
url("http://foo");
2591 std::vector
<NavigationEntry
*> entries
;
2592 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
2593 url
, Referrer(), ui::PAGE_TRANSITION_RELOAD
, false, std::string(),
2595 entry
->SetPageID(0);
2596 entry
->SetTitle(base::ASCIIToUTF16("Title"));
2597 entry
->SetPageState(PageState::CreateFromEncodedData("state"));
2598 entries
.push_back(entry
);
2599 scoped_ptr
<WebContentsImpl
> our_contents(static_cast<WebContentsImpl
*>(
2600 WebContents::Create(WebContents::CreateParams(browser_context()))));
2601 NavigationControllerImpl
& our_controller
= our_contents
->GetController();
2602 our_controller
.Restore(
2603 0, NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
, &entries
);
2604 ASSERT_EQ(0u, entries
.size());
2606 // Before navigating to the restored entry, it should have a restore_type
2607 // and no SiteInstance.
2608 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2609 our_controller
.GetEntryAtIndex(0)->restore_type());
2610 EXPECT_FALSE(our_controller
.GetEntryAtIndex(0)->site_instance());
2612 // After navigating, we should have one entry, and it should be "pending".
2613 // It should now have a SiteInstance and no restore_type.
2614 our_controller
.GoToIndex(0);
2615 EXPECT_EQ(1, our_controller
.GetEntryCount());
2616 EXPECT_EQ(our_controller
.GetEntryAtIndex(0),
2617 our_controller
.GetPendingEntry());
2618 EXPECT_EQ(0, our_controller
.GetEntryAtIndex(0)->GetPageID());
2619 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2620 our_controller
.GetEntryAtIndex(0)->restore_type());
2621 EXPECT_TRUE(our_controller
.GetEntryAtIndex(0)->site_instance());
2623 // This pending navigation may have caused a different navigation to fail,
2624 // which causes the pending entry to be cleared.
2625 FrameHostMsg_DidFailProvisionalLoadWithError_Params fail_load_params
;
2626 fail_load_params
.error_code
= net::ERR_ABORTED
;
2627 fail_load_params
.error_description
= base::string16();
2628 fail_load_params
.url
= url
;
2629 fail_load_params
.showing_repost_interstitial
= false;
2630 main_test_rfh()->OnMessageReceived(
2631 FrameHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
2634 // Now the pending restored entry commits.
2635 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2638 params
.transition
= ui::PAGE_TRANSITION_LINK
;
2639 params
.should_update_history
= false;
2640 params
.gesture
= NavigationGestureUser
;
2641 params
.is_post
= false;
2642 params
.page_state
= PageState::CreateFromURL(url
);
2643 LoadCommittedDetails details
;
2644 our_controller
.RendererDidNavigate(our_contents
->GetMainFrame(), params
,
2647 // There should be no pending entry and one committed one.
2648 EXPECT_EQ(1, our_controller
.GetEntryCount());
2649 EXPECT_EQ(0, our_controller
.GetLastCommittedEntryIndex());
2650 EXPECT_FALSE(our_controller
.GetPendingEntry());
2653 our_controller
.GetLastCommittedEntry()->site_instance()->GetSiteURL());
2654 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2655 our_controller
.GetEntryAtIndex(0)->restore_type());
2658 // Make sure that the page type and stuff is correct after an interstitial.
2659 TEST_F(NavigationControllerTest
, Interstitial
) {
2660 NavigationControllerImpl
& controller
= controller_impl();
2661 // First navigate somewhere normal.
2662 const GURL
url1("http://foo");
2664 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2665 main_test_rfh()->PrepareForCommit();
2666 main_test_rfh()->SendNavigate(0, url1
);
2668 // Now navigate somewhere with an interstitial.
2669 const GURL
url2("http://bar");
2670 controller
.LoadURL(url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
,
2672 controller
.GetPendingEntry()->set_page_type(PAGE_TYPE_INTERSTITIAL
);
2674 // At this point the interstitial will be displayed and the load will still
2675 // be pending. If the user continues, the load will commit.
2676 main_test_rfh()->PrepareForCommit();
2677 main_test_rfh()->SendNavigate(1, url2
);
2679 // The page should be a normal page again.
2680 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetURL());
2681 EXPECT_EQ(PAGE_TYPE_NORMAL
,
2682 controller
.GetLastCommittedEntry()->GetPageType());
2685 TEST_F(NavigationControllerTest
, RemoveEntry
) {
2686 NavigationControllerImpl
& controller
= controller_impl();
2687 const GURL
url1("http://foo/1");
2688 const GURL
url2("http://foo/2");
2689 const GURL
url3("http://foo/3");
2690 const GURL
url4("http://foo/4");
2691 const GURL
url5("http://foo/5");
2692 const GURL
pending_url("http://foo/pending");
2693 const GURL
default_url("http://foo/default");
2696 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2697 main_test_rfh()->PrepareForCommit();
2698 main_test_rfh()->SendNavigate(0, url1
);
2700 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2701 main_test_rfh()->PrepareForCommit();
2702 main_test_rfh()->SendNavigate(1, url2
);
2704 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2705 main_test_rfh()->PrepareForCommit();
2706 main_test_rfh()->SendNavigate(2, url3
);
2708 url4
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2709 main_test_rfh()->PrepareForCommit();
2710 main_test_rfh()->SendNavigate(3, url4
);
2712 url5
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2713 main_test_rfh()->PrepareForCommit();
2714 main_test_rfh()->SendNavigate(4, url5
);
2716 // Try to remove the last entry. Will fail because it is the current entry.
2717 EXPECT_FALSE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1));
2718 EXPECT_EQ(5, controller
.GetEntryCount());
2719 EXPECT_EQ(4, controller
.GetLastCommittedEntryIndex());
2721 // Go back, but don't commit yet. Check that we can't delete the current
2722 // and pending entries.
2723 controller
.GoBack();
2724 EXPECT_FALSE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1));
2725 EXPECT_FALSE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 2));
2727 // Now commit and delete the last entry.
2728 main_test_rfh()->PrepareForCommit();
2729 main_test_rfh()->SendNavigate(3, url4
);
2730 EXPECT_TRUE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1));
2731 EXPECT_EQ(4, controller
.GetEntryCount());
2732 EXPECT_EQ(3, controller
.GetLastCommittedEntryIndex());
2733 EXPECT_FALSE(controller
.GetPendingEntry());
2735 // Remove an entry which is not the last committed one.
2736 EXPECT_TRUE(controller
.RemoveEntryAtIndex(0));
2737 EXPECT_EQ(3, controller
.GetEntryCount());
2738 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
2739 EXPECT_FALSE(controller
.GetPendingEntry());
2741 // Remove the 2 remaining entries.
2742 controller
.RemoveEntryAtIndex(1);
2743 controller
.RemoveEntryAtIndex(0);
2745 // This should leave us with only the last committed entry.
2746 EXPECT_EQ(1, controller
.GetEntryCount());
2747 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
2750 TEST_F(NavigationControllerTest
, RemoveEntryWithPending
) {
2751 NavigationControllerImpl
& controller
= controller_impl();
2752 const GURL
url1("http://foo/1");
2753 const GURL
url2("http://foo/2");
2754 const GURL
url3("http://foo/3");
2755 const GURL
default_url("http://foo/default");
2758 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2759 main_test_rfh()->PrepareForCommit();
2760 main_test_rfh()->SendNavigate(0, url1
);
2762 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2763 main_test_rfh()->PrepareForCommit();
2764 main_test_rfh()->SendNavigate(1, url2
);
2766 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2767 main_test_rfh()->PrepareForCommit();
2768 main_test_rfh()->SendNavigate(2, url3
);
2770 // Go back, but don't commit yet. Check that we can't delete the current
2771 // and pending entries.
2772 controller
.GoBack();
2773 EXPECT_FALSE(controller
.RemoveEntryAtIndex(2));
2774 EXPECT_FALSE(controller
.RemoveEntryAtIndex(1));
2776 // Remove the first entry, while there is a pending entry. This is expected
2777 // to discard the pending entry.
2778 EXPECT_TRUE(controller
.RemoveEntryAtIndex(0));
2779 EXPECT_FALSE(controller
.GetPendingEntry());
2780 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
2782 // We should update the last committed entry index.
2783 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
2785 // Now commit and ensure we land on the right entry.
2786 main_test_rfh()->PrepareForCommit();
2787 main_test_rfh()->SendNavigate(1, url2
);
2788 EXPECT_EQ(2, controller
.GetEntryCount());
2789 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
2790 EXPECT_FALSE(controller
.GetPendingEntry());
2793 // Tests the transient entry, making sure it goes away with all navigations.
2794 TEST_F(NavigationControllerTest
, TransientEntry
) {
2795 NavigationControllerImpl
& controller
= controller_impl();
2796 TestNotificationTracker notifications
;
2797 RegisterForAllNavNotifications(¬ifications
, &controller
);
2799 const GURL
url0("http://foo/0");
2800 const GURL
url1("http://foo/1");
2801 const GURL
url2("http://foo/2");
2802 const GURL
url3("http://foo/3");
2803 const GURL
url3_ref("http://foo/3#bar");
2804 const GURL
url4("http://foo/4");
2805 const GURL
transient_url("http://foo/transient");
2808 url0
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2809 main_test_rfh()->PrepareForCommit();
2810 main_test_rfh()->SendNavigate(0, url0
);
2812 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2813 main_test_rfh()->PrepareForCommit();
2814 main_test_rfh()->SendNavigate(1, url1
);
2816 notifications
.Reset();
2818 // Adding a transient with no pending entry.
2819 NavigationEntryImpl
* transient_entry
= new NavigationEntryImpl
;
2820 transient_entry
->SetURL(transient_url
);
2821 controller
.SetTransientEntry(transient_entry
);
2823 // We should not have received any notifications.
2824 EXPECT_EQ(0U, notifications
.size());
2827 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2828 EXPECT_EQ(controller
.GetEntryCount(), 3);
2829 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
2830 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
2831 EXPECT_TRUE(controller
.GetLastCommittedEntry());
2832 EXPECT_FALSE(controller
.GetPendingEntry());
2833 EXPECT_TRUE(controller
.CanGoBack());
2834 EXPECT_FALSE(controller
.CanGoForward());
2835 EXPECT_EQ(contents()->GetMaxPageID(), 1);
2839 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2840 main_test_rfh()->PrepareForCommit();
2841 main_test_rfh()->SendNavigate(2, url2
);
2843 // We should have navigated, transient entry should be gone.
2844 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2845 EXPECT_EQ(controller
.GetEntryCount(), 3);
2847 // Add a transient again, then navigate with no pending entry this time.
2848 transient_entry
= new NavigationEntryImpl
;
2849 transient_entry
->SetURL(transient_url
);
2850 controller
.SetTransientEntry(transient_entry
);
2851 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2852 main_test_rfh()->SendRendererInitiatedNavigationRequest(url3
, true);
2853 main_test_rfh()->PrepareForCommit();
2854 main_test_rfh()->SendNavigate(3, url3
);
2855 // Transient entry should be gone.
2856 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2857 EXPECT_EQ(controller
.GetEntryCount(), 4);
2859 // Initiate a navigation, add a transient then commit navigation.
2861 url4
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2862 transient_entry
= new NavigationEntryImpl
;
2863 transient_entry
->SetURL(transient_url
);
2864 controller
.SetTransientEntry(transient_entry
);
2865 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2866 main_test_rfh()->PrepareForCommit();
2867 main_test_rfh()->SendNavigate(4, url4
);
2868 EXPECT_EQ(url4
, controller
.GetVisibleEntry()->GetURL());
2869 EXPECT_EQ(controller
.GetEntryCount(), 5);
2871 // Add a transient and go back. This should simply remove the transient.
2872 transient_entry
= new NavigationEntryImpl
;
2873 transient_entry
->SetURL(transient_url
);
2874 controller
.SetTransientEntry(transient_entry
);
2875 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2876 EXPECT_TRUE(controller
.CanGoBack());
2877 EXPECT_FALSE(controller
.CanGoForward());
2878 controller
.GoBack();
2879 // Transient entry should be gone.
2880 EXPECT_EQ(url4
, controller
.GetVisibleEntry()->GetURL());
2881 EXPECT_EQ(controller
.GetEntryCount(), 5);
2883 // Suppose the page requested a history navigation backward.
2884 controller
.GoToOffset(-1);
2885 main_test_rfh()->PrepareForCommit();
2886 main_test_rfh()->SendNavigate(3, url3
);
2888 // Add a transient and go to an entry before the current one.
2889 transient_entry
= new NavigationEntryImpl
;
2890 transient_entry
->SetURL(transient_url
);
2891 controller
.SetTransientEntry(transient_entry
);
2892 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2893 controller
.GoToIndex(1);
2894 // The navigation should have been initiated, transient entry should be gone.
2895 EXPECT_FALSE(controller
.GetTransientEntry());
2896 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
2897 // Visible entry does not update for history navigations until commit.
2898 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2899 main_test_rfh()->PrepareForCommit();
2900 main_test_rfh()->SendNavigate(1, url1
);
2901 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2903 // Add a transient and go to an entry after the current one.
2904 transient_entry
= new NavigationEntryImpl
;
2905 transient_entry
->SetURL(transient_url
);
2906 controller
.SetTransientEntry(transient_entry
);
2907 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2908 controller
.GoToIndex(3);
2909 // The navigation should have been initiated, transient entry should be gone.
2910 // Because of the transient entry that is removed, going to index 3 makes us
2911 // land on url2 (which is visible after the commit).
2912 EXPECT_EQ(url2
, controller
.GetPendingEntry()->GetURL());
2913 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2914 main_test_rfh()->PrepareForCommit();
2915 main_test_rfh()->SendNavigate(2, url2
);
2916 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2918 // Add a transient and go forward.
2919 transient_entry
= new NavigationEntryImpl
;
2920 transient_entry
->SetURL(transient_url
);
2921 controller
.SetTransientEntry(transient_entry
);
2922 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2923 EXPECT_TRUE(controller
.CanGoForward());
2924 controller
.GoForward();
2925 // We should have navigated, transient entry should be gone.
2926 EXPECT_FALSE(controller
.GetTransientEntry());
2927 EXPECT_EQ(url3
, controller
.GetPendingEntry()->GetURL());
2928 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2929 main_test_rfh()->PrepareForCommit();
2930 main_test_rfh()->SendNavigate(3, url3
);
2931 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2933 // Add a transient and do an in-page navigation, replacing the current entry.
2934 transient_entry
= new NavigationEntryImpl
;
2935 transient_entry
->SetURL(transient_url
);
2936 controller
.SetTransientEntry(transient_entry
);
2937 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2939 main_test_rfh()->SendRendererInitiatedNavigationRequest(url3_ref
, false);
2940 main_test_rfh()->PrepareForCommit();
2941 main_test_rfh()->SendNavigate(3, url3_ref
);
2942 // Transient entry should be gone.
2943 EXPECT_FALSE(controller
.GetTransientEntry());
2944 EXPECT_EQ(url3_ref
, controller
.GetVisibleEntry()->GetURL());
2946 // Ensure the URLs are correct.
2947 EXPECT_EQ(controller
.GetEntryCount(), 5);
2948 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2949 EXPECT_EQ(controller
.GetEntryAtIndex(1)->GetURL(), url1
);
2950 EXPECT_EQ(controller
.GetEntryAtIndex(2)->GetURL(), url2
);
2951 EXPECT_EQ(controller
.GetEntryAtIndex(3)->GetURL(), url3_ref
);
2952 EXPECT_EQ(controller
.GetEntryAtIndex(4)->GetURL(), url4
);
2955 // Test that Reload initiates a new navigation to a transient entry's URL.
2956 TEST_F(NavigationControllerTest
, ReloadTransient
) {
2957 NavigationControllerImpl
& controller
= controller_impl();
2958 const GURL
url0("http://foo/0");
2959 const GURL
url1("http://foo/1");
2960 const GURL
transient_url("http://foo/transient");
2962 // Load |url0|, and start a pending navigation to |url1|.
2964 url0
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2965 main_test_rfh()->PrepareForCommit();
2966 main_test_rfh()->SendNavigate(0, url0
);
2968 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2970 // A transient entry is added, interrupting the navigation.
2971 NavigationEntryImpl
* transient_entry
= new NavigationEntryImpl
;
2972 transient_entry
->SetURL(transient_url
);
2973 controller
.SetTransientEntry(transient_entry
);
2974 EXPECT_TRUE(controller
.GetTransientEntry());
2975 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2977 // The page is reloaded, which should remove the pending entry for |url1| and
2978 // the transient entry for |transient_url|, and start a navigation to
2980 controller
.Reload(true);
2981 EXPECT_FALSE(controller
.GetTransientEntry());
2982 EXPECT_TRUE(controller
.GetPendingEntry());
2983 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2984 ASSERT_EQ(controller
.GetEntryCount(), 1);
2985 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2987 // Load of |transient_url| completes.
2988 main_test_rfh()->PrepareForCommit();
2989 main_test_rfh()->SendNavigate(1, transient_url
);
2990 ASSERT_EQ(controller
.GetEntryCount(), 2);
2991 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2992 EXPECT_EQ(controller
.GetEntryAtIndex(1)->GetURL(), transient_url
);
2995 // Ensure that renderer initiated pending entries get replaced, so that we
2996 // don't show a stale virtual URL when a navigation commits.
2997 // See http://crbug.com/266922.
2998 TEST_F(NavigationControllerTest
, RendererInitiatedPendingEntries
) {
2999 NavigationControllerImpl
& controller
= controller_impl();
3000 Navigator
* navigator
=
3001 contents()->GetFrameTree()->root()->navigator();
3003 const GURL
url1("nonexistent:12121");
3004 const GURL
url1_fixed("http://nonexistent:12121/");
3005 const GURL
url2("http://foo");
3007 // We create pending entries for renderer-initiated navigations so that we
3008 // can show them in new tabs when it is safe.
3009 navigator
->DidStartProvisionalLoad(main_test_rfh(), url1
, false);
3011 // Simulate what happens if a BrowserURLHandler rewrites the URL, causing
3012 // the virtual URL to differ from the URL.
3013 controller
.GetPendingEntry()->SetURL(url1_fixed
);
3014 controller
.GetPendingEntry()->SetVirtualURL(url1
);
3016 EXPECT_EQ(url1_fixed
, controller
.GetPendingEntry()->GetURL());
3017 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetVirtualURL());
3018 EXPECT_TRUE(controller
.GetPendingEntry()->is_renderer_initiated());
3020 // If the user clicks another link, we should replace the pending entry.
3021 main_test_rfh()->SendRendererInitiatedNavigationRequest(url2
, false);
3022 main_test_rfh()->PrepareForCommit();
3023 navigator
->DidStartProvisionalLoad(main_test_rfh(), url2
, false);
3024 EXPECT_EQ(url2
, controller
.GetPendingEntry()->GetURL());
3025 EXPECT_EQ(url2
, controller
.GetPendingEntry()->GetVirtualURL());
3027 // Once it commits, the URL and virtual URL should reflect the actual page.
3028 main_test_rfh()->SendNavigate(0, url2
);
3029 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetURL());
3030 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetVirtualURL());
3032 // We should not replace the pending entry for an error URL.
3033 navigator
->DidStartProvisionalLoad(main_test_rfh(), url1
, false);
3034 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
3035 navigator
->DidStartProvisionalLoad(main_test_rfh(),
3036 GURL(kUnreachableWebDataURL
), false);
3037 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
3039 // We should remember if the pending entry will replace the current one.
3040 // http://crbug.com/308444.
3041 navigator
->DidStartProvisionalLoad(main_test_rfh(), url1
, false);
3042 controller
.GetPendingEntry()->set_should_replace_entry(true);
3044 main_test_rfh()->SendRendererInitiatedNavigationRequest(url2
, false);
3045 main_test_rfh()->PrepareForCommit();
3046 navigator
->DidStartProvisionalLoad(main_test_rfh(), url2
, false);
3047 EXPECT_TRUE(controller
.GetPendingEntry()->should_replace_entry());
3048 main_test_rfh()->SendNavigate(0, url2
);
3049 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetURL());
3052 // Tests that the URLs for renderer-initiated navigations are not displayed to
3053 // the user until the navigation commits, to prevent URL spoof attacks.
3054 // See http://crbug.com/99016.
3055 TEST_F(NavigationControllerTest
, DontShowRendererURLUntilCommit
) {
3056 NavigationControllerImpl
& controller
= controller_impl();
3057 TestNotificationTracker notifications
;
3058 RegisterForAllNavNotifications(¬ifications
, &controller
);
3060 const GURL
url0("http://foo/0");
3061 const GURL
url1("http://foo/1");
3063 // For typed navigations (browser-initiated), both pending and visible entries
3064 // should update before commit.
3066 url0
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
3067 EXPECT_EQ(url0
, controller
.GetPendingEntry()->GetURL());
3068 EXPECT_EQ(url0
, controller
.GetVisibleEntry()->GetURL());
3069 main_test_rfh()->PrepareForCommit();
3070 main_test_rfh()->SendNavigate(0, url0
);
3072 // For link clicks (renderer-initiated navigations), the pending entry should
3073 // update before commit but the visible should not.
3074 NavigationController::LoadURLParams
load_url_params(url1
);
3075 load_url_params
.is_renderer_initiated
= true;
3076 controller
.LoadURLWithParams(load_url_params
);
3077 EXPECT_EQ(url0
, controller
.GetVisibleEntry()->GetURL());
3078 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
3079 EXPECT_TRUE(controller
.GetPendingEntry()->is_renderer_initiated());
3081 // After commit, both visible should be updated, there should be no pending
3082 // entry, and we should no longer treat the entry as renderer-initiated.
3083 main_test_rfh()->PrepareForCommit();
3084 main_test_rfh()->SendNavigate(1, url1
);
3085 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
3086 EXPECT_FALSE(controller
.GetPendingEntry());
3087 EXPECT_FALSE(controller
.GetLastCommittedEntry()->is_renderer_initiated());
3089 notifications
.Reset();
3092 // Tests that the URLs for renderer-initiated navigations in new tabs are
3093 // displayed to the user before commit, as long as the initial about:blank
3094 // page has not been modified. If so, we must revert to showing about:blank.
3095 // See http://crbug.com/9682.
3096 TEST_F(NavigationControllerTest
, ShowRendererURLInNewTabUntilModified
) {
3097 NavigationControllerImpl
& controller
= controller_impl();
3098 TestNotificationTracker notifications
;
3099 RegisterForAllNavNotifications(¬ifications
, &controller
);
3101 const GURL
url("http://foo");
3103 // For renderer-initiated navigations in new tabs (with no committed entries),
3104 // we show the pending entry's URL as long as the about:blank page is not
3106 NavigationController::LoadURLParams
load_url_params(url
);
3107 load_url_params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
3108 load_url_params
.is_renderer_initiated
= true;
3109 controller
.LoadURLWithParams(load_url_params
);
3110 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
3111 EXPECT_EQ(url
, controller
.GetPendingEntry()->GetURL());
3112 EXPECT_TRUE(controller
.GetPendingEntry()->is_renderer_initiated());
3113 EXPECT_TRUE(controller
.IsInitialNavigation());
3114 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
3116 // There should be no title yet.
3117 EXPECT_TRUE(contents()->GetTitle().empty());
3119 // If something else modifies the contents of the about:blank page, then
3120 // we must revert to showing about:blank to avoid a URL spoof.
3121 main_test_rfh()->OnMessageReceived(FrameHostMsg_DidAccessInitialDocument(0));
3122 EXPECT_TRUE(contents()->HasAccessedInitialDocument());
3123 EXPECT_FALSE(controller
.GetVisibleEntry());
3124 EXPECT_EQ(url
, controller
.GetPendingEntry()->GetURL());
3126 notifications
.Reset();
3129 // Tests that the URLs for browser-initiated navigations in new tabs are
3130 // displayed to the user even after they fail, as long as the initial
3131 // about:blank page has not been modified. If so, we must revert to showing
3132 // about:blank. See http://crbug.com/355537.
3133 TEST_F(NavigationControllerTest
, ShowBrowserURLAfterFailUntilModified
) {
3134 NavigationControllerImpl
& controller
= controller_impl();
3135 TestNotificationTracker notifications
;
3136 RegisterForAllNavNotifications(¬ifications
, &controller
);
3138 const GURL
url("http://foo");
3140 // For browser-initiated navigations in new tabs (with no committed entries),
3141 // we show the pending entry's URL as long as the about:blank page is not
3142 // modified. This is possible in cases that the user types a URL into a popup
3143 // tab created with a slow URL.
3144 NavigationController::LoadURLParams
load_url_params(url
);
3145 load_url_params
.transition_type
= ui::PAGE_TRANSITION_TYPED
;
3146 load_url_params
.is_renderer_initiated
= false;
3147 controller
.LoadURLWithParams(load_url_params
);
3148 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
3149 EXPECT_EQ(url
, controller
.GetPendingEntry()->GetURL());
3150 EXPECT_FALSE(controller
.GetPendingEntry()->is_renderer_initiated());
3151 EXPECT_TRUE(controller
.IsInitialNavigation());
3152 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
3154 // There should be no title yet.
3155 EXPECT_TRUE(contents()->GetTitle().empty());
3157 // Suppose it aborts before committing, if it's a 204 or download or due to a
3158 // stop or a new navigation from the user. The URL should remain visible.
3159 FrameHostMsg_DidFailProvisionalLoadWithError_Params params
;
3160 params
.error_code
= net::ERR_ABORTED
;
3161 params
.error_description
= base::string16();
3163 params
.showing_repost_interstitial
= false;
3164 main_test_rfh()->OnMessageReceived(
3165 FrameHostMsg_DidFailProvisionalLoadWithError(0, params
));
3166 contents()->SetIsLoading(false, true, NULL
);
3167 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
3169 // If something else later modifies the contents of the about:blank page, then
3170 // we must revert to showing about:blank to avoid a URL spoof.
3171 main_test_rfh()->OnMessageReceived(FrameHostMsg_DidAccessInitialDocument(0));
3172 EXPECT_TRUE(contents()->HasAccessedInitialDocument());
3173 EXPECT_FALSE(controller
.GetVisibleEntry());
3174 EXPECT_FALSE(controller
.GetPendingEntry());
3176 notifications
.Reset();
3179 // Tests that the URLs for renderer-initiated navigations in new tabs are
3180 // displayed to the user even after they fail, as long as the initial
3181 // about:blank page has not been modified. If so, we must revert to showing
3182 // about:blank. See http://crbug.com/355537.
3183 TEST_F(NavigationControllerTest
, ShowRendererURLAfterFailUntilModified
) {
3184 NavigationControllerImpl
& controller
= controller_impl();
3185 TestNotificationTracker notifications
;
3186 RegisterForAllNavNotifications(¬ifications
, &controller
);
3188 const GURL
url("http://foo");
3190 // For renderer-initiated navigations in new tabs (with no committed entries),
3191 // we show the pending entry's URL as long as the about:blank page is not
3193 NavigationController::LoadURLParams
load_url_params(url
);
3194 load_url_params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
3195 load_url_params
.is_renderer_initiated
= true;
3196 controller
.LoadURLWithParams(load_url_params
);
3197 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
3198 EXPECT_EQ(url
, controller
.GetPendingEntry()->GetURL());
3199 EXPECT_TRUE(controller
.GetPendingEntry()->is_renderer_initiated());
3200 EXPECT_TRUE(controller
.IsInitialNavigation());
3201 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
3203 // There should be no title yet.
3204 EXPECT_TRUE(contents()->GetTitle().empty());
3206 // Suppose it aborts before committing, if it's a 204 or download or due to a
3207 // stop or a new navigation from the user. The URL should remain visible.
3208 FrameHostMsg_DidFailProvisionalLoadWithError_Params params
;
3209 params
.error_code
= net::ERR_ABORTED
;
3210 params
.error_description
= base::string16();
3212 params
.showing_repost_interstitial
= false;
3213 main_test_rfh()->OnMessageReceived(
3214 FrameHostMsg_DidFailProvisionalLoadWithError(0, params
));
3215 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
3217 // If something else later modifies the contents of the about:blank page, then
3218 // we must revert to showing about:blank to avoid a URL spoof.
3219 main_test_rfh()->OnMessageReceived(FrameHostMsg_DidAccessInitialDocument(0));
3220 EXPECT_TRUE(contents()->HasAccessedInitialDocument());
3221 EXPECT_FALSE(controller
.GetVisibleEntry());
3222 EXPECT_EQ(url
, controller
.GetPendingEntry()->GetURL());
3224 notifications
.Reset();
3227 TEST_F(NavigationControllerTest
, DontShowRendererURLInNewTabAfterCommit
) {
3228 NavigationControllerImpl
& controller
= controller_impl();
3229 TestNotificationTracker notifications
;
3230 RegisterForAllNavNotifications(¬ifications
, &controller
);
3232 const GURL
url1("http://foo/eh");
3233 const GURL
url2("http://foo/bee");
3235 // For renderer-initiated navigations in new tabs (with no committed entries),
3236 // we show the pending entry's URL as long as the about:blank page is not
3238 NavigationController::LoadURLParams
load_url_params(url1
);
3239 load_url_params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
3240 load_url_params
.is_renderer_initiated
= true;
3241 controller
.LoadURLWithParams(load_url_params
);
3242 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
3243 EXPECT_TRUE(controller
.GetPendingEntry()->is_renderer_initiated());
3244 EXPECT_TRUE(controller
.IsInitialNavigation());
3245 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
3247 // Simulate a commit and then starting a new pending navigation.
3248 main_test_rfh()->PrepareForCommit();
3249 main_test_rfh()->SendNavigate(0, url1
);
3250 NavigationController::LoadURLParams
load_url2_params(url2
);
3251 load_url2_params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
3252 load_url2_params
.is_renderer_initiated
= true;
3253 controller
.LoadURLWithParams(load_url2_params
);
3255 // We should not consider this an initial navigation, and thus should
3256 // not show the pending URL.
3257 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
3258 EXPECT_FALSE(controller
.IsInitialNavigation());
3259 EXPECT_TRUE(controller
.GetVisibleEntry());
3260 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
3262 notifications
.Reset();
3265 // Tests that IsInPageNavigation returns appropriate results. Prevents
3266 // regression for bug 1126349.
3267 TEST_F(NavigationControllerTest
, IsInPageNavigation
) {
3268 NavigationControllerImpl
& controller
= controller_impl();
3269 const GURL
url("http://www.google.com/home.html");
3271 // If the renderer claims it performed an in-page navigation from
3272 // about:blank, trust the renderer.
3273 // This can happen when an iframe is created and populated via
3274 // document.write(), then tries to perform a fragment navigation.
3275 // TODO(japhet): We should only trust the renderer if the about:blank
3276 // was the first document in the given frame, but we don't have enough
3277 // information to identify that case currently.
3278 const GURL
blank_url(url::kAboutBlankURL
);
3279 main_test_rfh()->NavigateAndCommitRendererInitiated(0, blank_url
);
3280 EXPECT_TRUE(controller
.IsURLInPageNavigation(url
, true,
3283 // Navigate to URL with no refs.
3284 main_test_rfh()->NavigateAndCommitRendererInitiated(0, url
);
3286 // Reloading the page is not an in-page navigation.
3287 EXPECT_FALSE(controller
.IsURLInPageNavigation(url
, false,
3289 const GURL
other_url("http://www.google.com/add.html");
3290 EXPECT_FALSE(controller
.IsURLInPageNavigation(other_url
, false,
3292 const GURL
url_with_ref("http://www.google.com/home.html#my_ref");
3293 EXPECT_TRUE(controller
.IsURLInPageNavigation(url_with_ref
, true,
3296 // Navigate to URL with refs.
3297 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url_with_ref
);
3299 // Reloading the page is not an in-page navigation.
3300 EXPECT_FALSE(controller
.IsURLInPageNavigation(url_with_ref
, false,
3302 EXPECT_FALSE(controller
.IsURLInPageNavigation(url
, false,
3304 EXPECT_FALSE(controller
.IsURLInPageNavigation(other_url
, false,
3306 const GURL
other_url_with_ref("http://www.google.com/home.html#my_other_ref");
3307 EXPECT_TRUE(controller
.IsURLInPageNavigation(other_url_with_ref
, true,
3310 // Going to the same url again will be considered in-page
3311 // if the renderer says it is even if the navigation type isn't IN_PAGE.
3312 EXPECT_TRUE(controller
.IsURLInPageNavigation(url_with_ref
, true,
3315 // Going back to the non ref url will be considered in-page if the navigation
3317 EXPECT_TRUE(controller
.IsURLInPageNavigation(url
, true,
3320 // If the renderer says this is a same-origin in-page navigation, believe it.
3321 // This is the pushState/replaceState case.
3322 EXPECT_TRUE(controller
.IsURLInPageNavigation(other_url
, true,
3325 // Test allow_universal_access_from_file_urls flag.
3326 const GURL
different_origin_url("http://www.example.com");
3327 MockRenderProcessHost
* rph
= main_test_rfh()->GetProcess();
3328 WebPreferences prefs
= test_rvh()->GetWebkitPreferences();
3329 prefs
.allow_universal_access_from_file_urls
= true;
3330 test_rvh()->UpdateWebkitPreferences(prefs
);
3331 prefs
= test_rvh()->GetWebkitPreferences();
3332 EXPECT_TRUE(prefs
.allow_universal_access_from_file_urls
);
3333 // Allow in page navigation if existing URL is file scheme.
3334 const GURL
file_url("file:///foo/index.html");
3335 main_test_rfh()->NavigateAndCommitRendererInitiated(0, file_url
);
3336 EXPECT_EQ(0, rph
->bad_msg_count());
3337 EXPECT_TRUE(controller
.IsURLInPageNavigation(different_origin_url
, true,
3339 EXPECT_EQ(0, rph
->bad_msg_count());
3340 // Don't honor allow_universal_access_from_file_urls if existing URL is
3342 main_test_rfh()->NavigateAndCommitRendererInitiated(0, url
);
3343 EXPECT_FALSE(controller
.IsURLInPageNavigation(different_origin_url
, true,
3345 EXPECT_EQ(1, rph
->bad_msg_count());
3347 // Remove allow_universal_access_from_file_urls flag.
3348 prefs
.allow_universal_access_from_file_urls
= false;
3349 test_rvh()->UpdateWebkitPreferences(prefs
);
3350 prefs
= test_rvh()->GetWebkitPreferences();
3351 EXPECT_FALSE(prefs
.allow_universal_access_from_file_urls
);
3353 // Don't believe the renderer if it claims a cross-origin navigation is
3355 EXPECT_EQ(1, rph
->bad_msg_count());
3356 EXPECT_FALSE(controller
.IsURLInPageNavigation(different_origin_url
, true,
3358 EXPECT_EQ(2, rph
->bad_msg_count());
3361 // Some pages can have subframes with the same base URL (minus the reference) as
3362 // the main page. Even though this is hard, it can happen, and we don't want
3363 // these subframe navigations to affect the toplevel document. They should
3364 // instead be ignored. http://crbug.com/5585
3365 TEST_F(NavigationControllerTest
, SameSubframe
) {
3366 NavigationControllerImpl
& controller
= controller_impl();
3367 // Navigate the main frame.
3368 const GURL
url("http://www.google.com/");
3369 main_test_rfh()->NavigateAndCommitRendererInitiated(0, url
);
3371 // We should be at the first navigation entry.
3372 EXPECT_EQ(controller
.GetEntryCount(), 1);
3373 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
3375 // Navigate a subframe that would normally count as in-page.
3376 const GURL
subframe("http://www.google.com/#");
3377 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
3379 params
.url
= subframe
;
3380 params
.transition
= ui::PAGE_TRANSITION_AUTO_SUBFRAME
;
3381 params
.should_update_history
= false;
3382 params
.gesture
= NavigationGestureAuto
;
3383 params
.is_post
= false;
3384 params
.page_state
= PageState::CreateFromURL(subframe
);
3385 LoadCommittedDetails details
;
3386 EXPECT_FALSE(controller
.RendererDidNavigate(main_test_rfh(), params
,
3389 // Nothing should have changed.
3390 EXPECT_EQ(controller
.GetEntryCount(), 1);
3391 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
3394 // Make sure that on cloning a WebContentsImpl and going back needs_reload is
3396 TEST_F(NavigationControllerTest
, CloneAndGoBack
) {
3397 NavigationControllerImpl
& controller
= controller_impl();
3398 const GURL
url1("http://foo1");
3399 const GURL
url2("http://foo2");
3400 const base::string16
title(base::ASCIIToUTF16("Title"));
3402 NavigateAndCommit(url1
);
3403 controller
.GetVisibleEntry()->SetTitle(title
);
3404 NavigateAndCommit(url2
);
3406 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
3408 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
3409 EXPECT_TRUE(clone
->GetController().NeedsReload());
3410 clone
->GetController().GoBack();
3411 // Navigating back should have triggered needs_reload_ to go false.
3412 EXPECT_FALSE(clone
->GetController().NeedsReload());
3414 // Ensure that the pending URL and its title are visible.
3415 EXPECT_EQ(url1
, clone
->GetController().GetVisibleEntry()->GetURL());
3416 EXPECT_EQ(title
, clone
->GetTitle());
3419 // Make sure that reloading a cloned tab doesn't change its pending entry index.
3420 // See http://crbug.com/234491.
3421 TEST_F(NavigationControllerTest
, CloneAndReload
) {
3422 NavigationControllerImpl
& controller
= controller_impl();
3423 const GURL
url1("http://foo1");
3424 const GURL
url2("http://foo2");
3425 const base::string16
title(base::ASCIIToUTF16("Title"));
3427 NavigateAndCommit(url1
);
3428 controller
.GetVisibleEntry()->SetTitle(title
);
3429 NavigateAndCommit(url2
);
3431 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
3432 clone
->GetController().LoadIfNecessary();
3434 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
3435 EXPECT_EQ(1, clone
->GetController().GetPendingEntryIndex());
3437 clone
->GetController().Reload(true);
3438 EXPECT_EQ(1, clone
->GetController().GetPendingEntryIndex());
3441 // Make sure that cloning a WebContentsImpl doesn't copy interstitials.
3442 TEST_F(NavigationControllerTest
, CloneOmitsInterstitials
) {
3443 NavigationControllerImpl
& controller
= controller_impl();
3444 const GURL
url1("http://foo1");
3445 const GURL
url2("http://foo2");
3447 NavigateAndCommit(url1
);
3448 NavigateAndCommit(url2
);
3450 // Add an interstitial entry. Should be deleted with controller.
3451 NavigationEntryImpl
* interstitial_entry
= new NavigationEntryImpl();
3452 interstitial_entry
->set_page_type(PAGE_TYPE_INTERSTITIAL
);
3453 controller
.SetTransientEntry(interstitial_entry
);
3455 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
3457 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
3460 // Test requesting and triggering a lazy reload.
3461 TEST_F(NavigationControllerTest
, LazyReload
) {
3462 NavigationControllerImpl
& controller
= controller_impl();
3463 const GURL
url("http://foo");
3464 NavigateAndCommit(url
);
3465 ASSERT_FALSE(controller
.NeedsReload());
3466 EXPECT_NE(ui::PAGE_TRANSITION_RELOAD
,
3467 controller
.GetLastCommittedEntry()->GetTransitionType());
3469 // Request a reload to happen when the controller becomes active (e.g. after
3470 // the renderer gets killed in background on Android).
3471 controller
.SetNeedsReload();
3472 ASSERT_TRUE(controller
.NeedsReload());
3473 EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD
,
3474 controller
.GetLastCommittedEntry()->GetTransitionType());
3476 // Set the controller as active, triggering the requested reload.
3477 controller
.SetActive(true);
3478 ASSERT_FALSE(controller
.NeedsReload());
3479 EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD
,
3480 controller
.GetPendingEntry()->GetTransitionType());
3483 // Test requesting and triggering a lazy reload without any committed entry.
3484 TEST_F(NavigationControllerTest
, LazyReloadWithoutCommittedEntry
) {
3485 NavigationControllerImpl
& controller
= controller_impl();
3486 const GURL
url("http://foo");
3487 controller
.LoadURL(url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
3488 ASSERT_FALSE(controller
.NeedsReload());
3489 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
,
3490 controller
.GetPendingEntry()->GetTransitionType());
3492 // Request a reload to happen when the controller becomes active (e.g. after
3493 // the renderer gets killed in background on Android).
3494 controller
.SetNeedsReload();
3495 ASSERT_TRUE(controller
.NeedsReload());
3496 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
,
3497 controller
.GetPendingEntry()->GetTransitionType());
3499 // Set the controller as active, triggering the requested reload.
3500 controller
.SetActive(true);
3501 ASSERT_FALSE(controller
.NeedsReload());
3502 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
,
3503 controller
.GetPendingEntry()->GetTransitionType());
3506 // Tests a subframe navigation while a toplevel navigation is pending.
3507 // http://crbug.com/43967
3508 TEST_F(NavigationControllerTest
, SubframeWhilePending
) {
3509 NavigationControllerImpl
& controller
= controller_impl();
3510 // Load the first page.
3511 const GURL
url1("http://foo/");
3512 NavigateAndCommit(url1
);
3514 // Now start a pending load to a totally different page, but don't commit it.
3515 const GURL
url2("http://bar/");
3517 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
3519 // Send a subframe update from the first page, as if one had just
3520 // automatically loaded. Auto subframes don't increment the page ID.
3521 const GURL
url1_sub("http://foo/subframe");
3522 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
3523 params
.page_id
= controller
.GetLastCommittedEntry()->GetPageID();
3524 params
.url
= url1_sub
;
3525 params
.transition
= ui::PAGE_TRANSITION_AUTO_SUBFRAME
;
3526 params
.should_update_history
= false;
3527 params
.gesture
= NavigationGestureAuto
;
3528 params
.is_post
= false;
3529 params
.page_state
= PageState::CreateFromURL(url1_sub
);
3530 LoadCommittedDetails details
;
3532 // This should return false meaning that nothing was actually updated.
3533 EXPECT_FALSE(controller
.RendererDidNavigate(main_test_rfh(), params
,
3536 // The notification should have updated the last committed one, and not
3537 // the pending load.
3538 EXPECT_EQ(url1
, controller
.GetLastCommittedEntry()->GetURL());
3540 // The active entry should be unchanged by the subframe load.
3541 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
3544 // Test CopyStateFrom with 2 urls, the first selected and nothing in the target.
3545 TEST_F(NavigationControllerTest
, CopyStateFrom
) {
3546 NavigationControllerImpl
& controller
= controller_impl();
3547 const GURL
url1("http://foo1");
3548 const GURL
url2("http://foo2");
3550 NavigateAndCommit(url1
);
3551 NavigateAndCommit(url2
);
3552 controller
.GoBack();
3553 contents()->CommitPendingNavigation();
3555 scoped_ptr
<TestWebContents
> other_contents(
3556 static_cast<TestWebContents
*>(CreateTestWebContents()));
3557 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3558 other_controller
.CopyStateFrom(controller
);
3560 // other_controller should now contain 2 urls.
3561 ASSERT_EQ(2, other_controller
.GetEntryCount());
3562 // We should be looking at the first one.
3563 ASSERT_EQ(0, other_controller
.GetCurrentEntryIndex());
3565 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3566 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
3567 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3568 // This is a different site than url1, so the IDs start again at 0.
3569 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(1)->GetPageID());
3571 // The max page ID map should be copied over and updated with the max page ID
3572 // from the current tab.
3573 SiteInstance
* instance1
=
3574 other_controller
.GetEntryAtIndex(0)->site_instance();
3575 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3577 // Ensure the SessionStorageNamespaceMaps are the same size and have
3578 // the same partitons loaded.
3580 // TODO(ajwong): We should load a url from a different partition earlier
3581 // to make sure this map has more than one entry.
3582 const SessionStorageNamespaceMap
& session_storage_namespace_map
=
3583 controller
.GetSessionStorageNamespaceMap();
3584 const SessionStorageNamespaceMap
& other_session_storage_namespace_map
=
3585 other_controller
.GetSessionStorageNamespaceMap();
3586 EXPECT_EQ(session_storage_namespace_map
.size(),
3587 other_session_storage_namespace_map
.size());
3588 for (SessionStorageNamespaceMap::const_iterator it
=
3589 session_storage_namespace_map
.begin();
3590 it
!= session_storage_namespace_map
.end();
3592 SessionStorageNamespaceMap::const_iterator other
=
3593 other_session_storage_namespace_map
.find(it
->first
);
3594 EXPECT_TRUE(other
!= other_session_storage_namespace_map
.end());
3598 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
3599 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune
) {
3600 NavigationControllerImpl
& controller
= controller_impl();
3601 const GURL
url1("http://foo/1");
3602 const GURL
url2("http://foo/2");
3603 const GURL
url3("http://foo/3");
3605 NavigateAndCommit(url1
);
3606 NavigateAndCommit(url2
);
3608 // First two entries should have the same SiteInstance.
3609 SiteInstance
* instance1
= controller
.GetEntryAtIndex(0)->site_instance();
3610 SiteInstance
* instance2
= controller
.GetEntryAtIndex(1)->site_instance();
3611 EXPECT_EQ(instance1
, instance2
);
3612 EXPECT_EQ(0, controller
.GetEntryAtIndex(0)->GetPageID());
3613 EXPECT_EQ(1, controller
.GetEntryAtIndex(1)->GetPageID());
3614 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1
));
3616 scoped_ptr
<TestWebContents
> other_contents(
3617 static_cast<TestWebContents
*>(CreateTestWebContents()));
3618 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3619 other_contents
->NavigateAndCommit(url3
);
3620 other_contents
->ExpectSetHistoryOffsetAndLength(2, 3);
3621 other_controller
.CopyStateFromAndPrune(&controller
, false);
3623 // other_controller should now contain the 3 urls: url1, url2 and url3.
3625 ASSERT_EQ(3, other_controller
.GetEntryCount());
3627 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3629 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3630 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3631 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
3632 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
3633 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(1)->GetPageID());
3634 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3636 // A new SiteInstance in a different BrowsingInstance should be used for the
3638 SiteInstance
* instance3
=
3639 other_controller
.GetEntryAtIndex(2)->site_instance();
3640 EXPECT_NE(instance3
, instance1
);
3641 EXPECT_FALSE(instance3
->IsRelatedSiteInstance(instance1
));
3643 // The max page ID map should be copied over and updated with the max page ID
3644 // from the current tab.
3645 EXPECT_EQ(1, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3646 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance3
));
3649 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry in
3651 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune2
) {
3652 NavigationControllerImpl
& controller
= controller_impl();
3653 const GURL
url1("http://foo1");
3654 const GURL
url2("http://foo2");
3655 const GURL
url3("http://foo3");
3657 NavigateAndCommit(url1
);
3658 NavigateAndCommit(url2
);
3659 controller
.GoBack();
3660 contents()->CommitPendingNavigation();
3662 scoped_ptr
<TestWebContents
> other_contents(
3663 static_cast<TestWebContents
*>(CreateTestWebContents()));
3664 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3665 other_contents
->NavigateAndCommit(url3
);
3666 other_contents
->ExpectSetHistoryOffsetAndLength(1, 2);
3667 other_controller
.CopyStateFromAndPrune(&controller
, false);
3669 // other_controller should now contain: url1, url3
3671 ASSERT_EQ(2, other_controller
.GetEntryCount());
3672 ASSERT_EQ(1, other_controller
.GetCurrentEntryIndex());
3674 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3675 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3676 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(1)->GetPageID());
3678 // The max page ID map should be copied over and updated with the max page ID
3679 // from the current tab.
3680 SiteInstance
* instance1
=
3681 other_controller
.GetEntryAtIndex(1)->site_instance();
3682 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3685 // Test CopyStateFromAndPrune with 2 urls, the last selected and 2 entries in
3687 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune3
) {
3688 NavigationControllerImpl
& controller
= controller_impl();
3689 const GURL
url1("http://foo1");
3690 const GURL
url2("http://foo2");
3691 const GURL
url3("http://foo3");
3692 const GURL
url4("http://foo4");
3694 NavigateAndCommit(url1
);
3695 NavigateAndCommit(url2
);
3697 scoped_ptr
<TestWebContents
> other_contents(
3698 static_cast<TestWebContents
*>(CreateTestWebContents()));
3699 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3700 other_contents
->NavigateAndCommit(url3
);
3701 other_contents
->NavigateAndCommit(url4
);
3702 other_contents
->ExpectSetHistoryOffsetAndLength(2, 3);
3703 other_controller
.CopyStateFromAndPrune(&controller
, false);
3705 // other_controller should now contain: url1, url2, url4
3707 ASSERT_EQ(3, other_controller
.GetEntryCount());
3708 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3710 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3711 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3712 EXPECT_EQ(url4
, other_controller
.GetEntryAtIndex(2)->GetURL());
3714 // The max page ID map should be copied over and updated with the max page ID
3715 // from the current tab.
3716 SiteInstance
* instance1
=
3717 other_controller
.GetEntryAtIndex(2)->site_instance();
3718 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3721 // Test CopyStateFromAndPrune with 2 urls, 2 entries in the target, with
3722 // not the last entry selected in the target.
3723 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneNotLast
) {
3724 NavigationControllerImpl
& controller
= controller_impl();
3725 const GURL
url1("http://foo1");
3726 const GURL
url2("http://foo2");
3727 const GURL
url3("http://foo3");
3728 const GURL
url4("http://foo4");
3730 NavigateAndCommit(url1
);
3731 NavigateAndCommit(url2
);
3733 scoped_ptr
<TestWebContents
> other_contents(
3734 static_cast<TestWebContents
*>(CreateTestWebContents()));
3735 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3736 other_contents
->NavigateAndCommit(url3
);
3737 other_contents
->NavigateAndCommit(url4
);
3738 other_controller
.GoBack();
3739 other_contents
->CommitPendingNavigation();
3740 other_contents
->ExpectSetHistoryOffsetAndLength(2, 3);
3741 other_controller
.CopyStateFromAndPrune(&controller
, false);
3743 // other_controller should now contain: url1, url2, url3
3745 ASSERT_EQ(3, other_controller
.GetEntryCount());
3746 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3748 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3749 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3750 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
3752 // The max page ID map should be copied over and updated with the max page ID
3753 // from the current tab.
3754 SiteInstance
* instance1
=
3755 other_controller
.GetEntryAtIndex(2)->site_instance();
3756 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3759 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry plus
3760 // a pending entry in the target.
3761 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneTargetPending
) {
3762 NavigationControllerImpl
& controller
= controller_impl();
3763 const GURL
url1("http://foo1");
3764 const GURL
url2("http://foo2");
3765 const GURL
url3("http://foo3");
3766 const GURL
url4("http://foo4");
3768 NavigateAndCommit(url1
);
3769 NavigateAndCommit(url2
);
3770 controller
.GoBack();
3771 contents()->CommitPendingNavigation();
3773 scoped_ptr
<TestWebContents
> other_contents(
3774 static_cast<TestWebContents
*>(CreateTestWebContents()));
3775 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3776 other_contents
->NavigateAndCommit(url3
);
3777 other_controller
.LoadURL(
3778 url4
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
3779 other_contents
->ExpectSetHistoryOffsetAndLength(1, 2);
3780 other_controller
.CopyStateFromAndPrune(&controller
, false);
3782 // other_controller should now contain url1, url3, and a pending entry
3785 ASSERT_EQ(2, other_controller
.GetEntryCount());
3786 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
3788 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3789 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3791 // And there should be a pending entry for url4.
3792 ASSERT_TRUE(other_controller
.GetPendingEntry());
3793 EXPECT_EQ(url4
, other_controller
.GetPendingEntry()->GetURL());
3795 // The max page ID map should be copied over and updated with the max page ID
3796 // from the current tab.
3797 SiteInstance
* instance1
=
3798 other_controller
.GetEntryAtIndex(0)->site_instance();
3799 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3802 // Test CopyStateFromAndPrune with 1 url in the source, 1 entry and a pending
3803 // client redirect entry (with the same page ID) in the target. This used to
3804 // crash because the last committed entry would be pruned but max_page_id
3805 // remembered the page ID (http://crbug.com/234809).
3806 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneTargetPending2
) {
3807 NavigationControllerImpl
& controller
= controller_impl();
3808 const GURL
url1("http://foo1");
3809 const GURL
url2a("http://foo2/a");
3810 const GURL
url2b("http://foo2/b");
3812 NavigateAndCommit(url1
);
3814 scoped_ptr
<TestWebContents
> other_contents(
3815 static_cast<TestWebContents
*>(CreateTestWebContents()));
3816 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3817 other_contents
->NavigateAndCommit(url2a
);
3818 // Simulate a client redirect, which has the same page ID as entry 2a.
3819 other_controller
.LoadURL(
3820 url2b
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
3821 other_controller
.GetPendingEntry()->SetPageID(
3822 other_controller
.GetLastCommittedEntry()->GetPageID());
3824 other_contents
->ExpectSetHistoryOffsetAndLength(1, 2);
3825 other_controller
.CopyStateFromAndPrune(&controller
, false);
3827 // other_controller should now contain url1, url2a, and a pending entry
3830 ASSERT_EQ(2, other_controller
.GetEntryCount());
3831 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
3833 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3834 EXPECT_EQ(url2a
, other_controller
.GetEntryAtIndex(1)->GetURL());
3836 // And there should be a pending entry for url4.
3837 ASSERT_TRUE(other_controller
.GetPendingEntry());
3838 EXPECT_EQ(url2b
, other_controller
.GetPendingEntry()->GetURL());
3840 // Let the pending entry commit.
3841 other_contents
->CommitPendingNavigation();
3843 // The max page ID map should be copied over and updated with the max page ID
3844 // from the current tab.
3845 SiteInstance
* instance1
=
3846 other_controller
.GetEntryAtIndex(1)->site_instance();
3847 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3850 // Test CopyStateFromAndPrune with 2 urls, a back navigation pending in the
3851 // source, and 1 entry in the target. The back pending entry should be ignored.
3852 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneSourcePending
) {
3853 NavigationControllerImpl
& controller
= controller_impl();
3854 const GURL
url1("http://foo1");
3855 const GURL
url2("http://foo2");
3856 const GURL
url3("http://foo3");
3858 NavigateAndCommit(url1
);
3859 NavigateAndCommit(url2
);
3860 controller
.GoBack();
3862 scoped_ptr
<TestWebContents
> other_contents(
3863 static_cast<TestWebContents
*>(CreateTestWebContents()));
3864 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3865 other_contents
->NavigateAndCommit(url3
);
3866 other_contents
->ExpectSetHistoryOffsetAndLength(2, 3);
3867 other_controller
.CopyStateFromAndPrune(&controller
, false);
3869 // other_controller should now contain: url1, url2, url3
3871 ASSERT_EQ(3, other_controller
.GetEntryCount());
3872 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3874 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3875 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3876 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
3877 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3879 // The max page ID map should be copied over and updated with the max page ID
3880 // from the current tab.
3881 SiteInstance
* instance1
=
3882 other_controller
.GetEntryAtIndex(2)->site_instance();
3883 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3886 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest,
3887 // when the max entry count is 3. We should prune one entry.
3888 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneMaxEntries
) {
3889 NavigationControllerImpl
& controller
= controller_impl();
3890 size_t original_count
= NavigationControllerImpl::max_entry_count();
3891 const int kMaxEntryCount
= 3;
3893 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
3895 const GURL
url1("http://foo/1");
3896 const GURL
url2("http://foo/2");
3897 const GURL
url3("http://foo/3");
3898 const GURL
url4("http://foo/4");
3900 // Create a PrunedListener to observe prune notifications.
3901 PrunedListener
listener(&controller
);
3903 NavigateAndCommit(url1
);
3904 NavigateAndCommit(url2
);
3905 NavigateAndCommit(url3
);
3907 scoped_ptr
<TestWebContents
> other_contents(
3908 static_cast<TestWebContents
*>(CreateTestWebContents()));
3909 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3910 other_contents
->NavigateAndCommit(url4
);
3911 other_contents
->ExpectSetHistoryOffsetAndLength(2, 3);
3912 other_controller
.CopyStateFromAndPrune(&controller
, false);
3914 // We should have received a pruned notification.
3915 EXPECT_EQ(1, listener
.notification_count_
);
3916 EXPECT_TRUE(listener
.details_
.from_front
);
3917 EXPECT_EQ(1, listener
.details_
.count
);
3919 // other_controller should now contain only 3 urls: url2, url3 and url4.
3921 ASSERT_EQ(3, other_controller
.GetEntryCount());
3923 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3925 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(0)->GetURL());
3926 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3927 EXPECT_EQ(url4
, other_controller
.GetEntryAtIndex(2)->GetURL());
3928 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(0)->GetPageID());
3929 EXPECT_EQ(2, other_controller
.GetEntryAtIndex(1)->GetPageID());
3930 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3932 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
3935 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest, with
3936 // replace_entry set to true.
3937 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneReplaceEntry
) {
3938 NavigationControllerImpl
& controller
= controller_impl();
3939 const GURL
url1("http://foo/1");
3940 const GURL
url2("http://foo/2");
3941 const GURL
url3("http://foo/3");
3943 NavigateAndCommit(url1
);
3944 NavigateAndCommit(url2
);
3946 // First two entries should have the same SiteInstance.
3947 SiteInstance
* instance1
= controller
.GetEntryAtIndex(0)->site_instance();
3948 SiteInstance
* instance2
= controller
.GetEntryAtIndex(1)->site_instance();
3949 EXPECT_EQ(instance1
, instance2
);
3950 EXPECT_EQ(0, controller
.GetEntryAtIndex(0)->GetPageID());
3951 EXPECT_EQ(1, controller
.GetEntryAtIndex(1)->GetPageID());
3952 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1
));
3954 scoped_ptr
<TestWebContents
> other_contents(
3955 static_cast<TestWebContents
*>(CreateTestWebContents()));
3956 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3957 other_contents
->NavigateAndCommit(url3
);
3958 other_contents
->ExpectSetHistoryOffsetAndLength(1, 2);
3959 other_controller
.CopyStateFromAndPrune(&controller
, true);
3961 // other_controller should now contain the 2 urls: url1 and url3.
3963 ASSERT_EQ(2, other_controller
.GetEntryCount());
3965 ASSERT_EQ(1, other_controller
.GetCurrentEntryIndex());
3967 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3968 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3969 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
3970 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(1)->GetPageID());
3972 // A new SiteInstance in a different BrowsingInstance should be used for the
3974 SiteInstance
* instance3
=
3975 other_controller
.GetEntryAtIndex(1)->site_instance();
3976 EXPECT_NE(instance3
, instance1
);
3977 EXPECT_FALSE(instance3
->IsRelatedSiteInstance(instance1
));
3979 // The max page ID map should be copied over and updated with the max page ID
3980 // from the current tab.
3981 EXPECT_EQ(1, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3982 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance3
));
3985 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest, when the max
3986 // entry count is 3 and replace_entry is true. We should not prune entries.
3987 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneMaxEntriesReplaceEntry
) {
3988 NavigationControllerImpl
& controller
= controller_impl();
3989 size_t original_count
= NavigationControllerImpl::max_entry_count();
3990 const int kMaxEntryCount
= 3;
3992 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
3994 const GURL
url1("http://foo/1");
3995 const GURL
url2("http://foo/2");
3996 const GURL
url3("http://foo/3");
3997 const GURL
url4("http://foo/4");
3999 // Create a PrunedListener to observe prune notifications.
4000 PrunedListener
listener(&controller
);
4002 NavigateAndCommit(url1
);
4003 NavigateAndCommit(url2
);
4004 NavigateAndCommit(url3
);
4006 scoped_ptr
<TestWebContents
> other_contents(
4007 static_cast<TestWebContents
*>(CreateTestWebContents()));
4008 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
4009 other_contents
->NavigateAndCommit(url4
);
4010 other_contents
->ExpectSetHistoryOffsetAndLength(2, 3);
4011 other_controller
.CopyStateFromAndPrune(&controller
, true);
4013 // We should have received no pruned notification.
4014 EXPECT_EQ(0, listener
.notification_count_
);
4016 // other_controller should now contain only 3 urls: url1, url2 and url4.
4018 ASSERT_EQ(3, other_controller
.GetEntryCount());
4020 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
4022 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
4023 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
4024 EXPECT_EQ(url4
, other_controller
.GetEntryAtIndex(2)->GetURL());
4025 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
4026 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(1)->GetPageID());
4027 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
4029 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
4032 // Tests that we can navigate to the restored entries
4033 // imported by CopyStateFromAndPrune.
4034 TEST_F(NavigationControllerTest
, CopyRestoredStateAndNavigate
) {
4035 const GURL kRestoredUrls
[] = {
4036 GURL("http://site1.com"),
4037 GURL("http://site2.com"),
4039 const GURL
kInitialUrl("http://site3.com");
4041 std::vector
<NavigationEntry
*> entries
;
4042 for (size_t i
= 0; i
< arraysize(kRestoredUrls
); ++i
) {
4043 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
4044 kRestoredUrls
[i
], Referrer(), ui::PAGE_TRANSITION_RELOAD
, false,
4045 std::string(), browser_context());
4046 entry
->SetPageID(static_cast<int>(i
));
4047 entries
.push_back(entry
);
4050 // Create a WebContents with restored entries.
4051 scoped_ptr
<TestWebContents
> source_contents(
4052 static_cast<TestWebContents
*>(CreateTestWebContents()));
4053 NavigationControllerImpl
& source_controller
=
4054 source_contents
->GetController();
4055 source_controller
.Restore(
4057 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
4059 ASSERT_EQ(0u, entries
.size());
4060 source_controller
.LoadIfNecessary();
4061 source_contents
->CommitPendingNavigation();
4063 // Load a page, then copy state from |source_contents|.
4064 NavigateAndCommit(kInitialUrl
);
4065 contents()->ExpectSetHistoryOffsetAndLength(2, 3);
4066 controller_impl().CopyStateFromAndPrune(&source_controller
, false);
4067 ASSERT_EQ(3, controller_impl().GetEntryCount());
4069 // Go back to the first entry one at a time and
4070 // verify that it works as expected.
4071 EXPECT_EQ(2, controller_impl().GetCurrentEntryIndex());
4072 EXPECT_EQ(kInitialUrl
, controller_impl().GetActiveEntry()->GetURL());
4074 controller_impl().GoBack();
4075 contents()->CommitPendingNavigation();
4076 EXPECT_EQ(1, controller_impl().GetCurrentEntryIndex());
4077 EXPECT_EQ(kRestoredUrls
[1], controller_impl().GetActiveEntry()->GetURL());
4079 controller_impl().GoBack();
4080 contents()->CommitPendingNavigation();
4081 EXPECT_EQ(0, controller_impl().GetCurrentEntryIndex());
4082 EXPECT_EQ(kRestoredUrls
[0], controller_impl().GetActiveEntry()->GetURL());
4085 // Tests that navigations initiated from the page (with the history object)
4086 // work as expected, creating pending entries.
4087 TEST_F(NavigationControllerTest
, HistoryNavigate
) {
4088 NavigationControllerImpl
& controller
= controller_impl();
4089 const GURL
url1("http://foo/1");
4090 const GURL
url2("http://foo/2");
4091 const GURL
url3("http://foo/3");
4093 NavigateAndCommit(url1
);
4094 NavigateAndCommit(url2
);
4095 NavigateAndCommit(url3
);
4096 controller
.GoBack();
4097 contents()->CommitPendingNavigation();
4098 process()->sink().ClearMessages();
4100 // Simulate the page calling history.back(). It should create a pending entry.
4101 contents()->OnGoToEntryAtOffset(-1);
4102 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
4103 // The actual cross-navigation is suspended until the current RVH tells us
4104 // it unloaded, simulate that.
4105 contents()->ProceedWithCrossSiteNavigation();
4106 // Also make sure we told the page to navigate.
4107 GURL nav_url
= GetLastNavigationURL();
4108 EXPECT_EQ(url1
, nav_url
);
4109 contents()->CommitPendingNavigation();
4110 process()->sink().ClearMessages();
4112 // Now test history.forward()
4113 contents()->OnGoToEntryAtOffset(2);
4114 EXPECT_EQ(2, controller
.GetPendingEntryIndex());
4115 // The actual cross-navigation is suspended until the current RVH tells us
4116 // it unloaded, simulate that.
4117 contents()->ProceedWithCrossSiteNavigation();
4118 nav_url
= GetLastNavigationURL();
4119 EXPECT_EQ(url3
, nav_url
);
4120 contents()->CommitPendingNavigation();
4121 process()->sink().ClearMessages();
4123 controller
.DiscardNonCommittedEntries();
4125 // Make sure an extravagant history.go() doesn't break.
4126 contents()->OnGoToEntryAtOffset(120); // Out of bounds.
4127 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
4128 EXPECT_FALSE(HasNavigationRequest());
4131 // Test call to PruneAllButLastCommitted for the only entry.
4132 TEST_F(NavigationControllerTest
, PruneAllButLastCommittedForSingle
) {
4133 NavigationControllerImpl
& controller
= controller_impl();
4134 const GURL
url1("http://foo1");
4135 NavigateAndCommit(url1
);
4137 contents()->ExpectSetHistoryOffsetAndLength(0, 1);
4139 controller
.PruneAllButLastCommitted();
4141 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
4142 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url1
);
4145 // Test call to PruneAllButLastCommitted for first entry.
4146 TEST_F(NavigationControllerTest
, PruneAllButLastCommittedForFirst
) {
4147 NavigationControllerImpl
& controller
= controller_impl();
4148 const GURL
url1("http://foo/1");
4149 const GURL
url2("http://foo/2");
4150 const GURL
url3("http://foo/3");
4152 NavigateAndCommit(url1
);
4153 NavigateAndCommit(url2
);
4154 NavigateAndCommit(url3
);
4155 controller
.GoBack();
4156 controller
.GoBack();
4157 contents()->CommitPendingNavigation();
4159 contents()->ExpectSetHistoryOffsetAndLength(0, 1);
4161 controller
.PruneAllButLastCommitted();
4163 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
4164 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url1
);
4167 // Test call to PruneAllButLastCommitted for intermediate entry.
4168 TEST_F(NavigationControllerTest
, PruneAllButLastCommittedForIntermediate
) {
4169 NavigationControllerImpl
& controller
= controller_impl();
4170 const GURL
url1("http://foo/1");
4171 const GURL
url2("http://foo/2");
4172 const GURL
url3("http://foo/3");
4174 NavigateAndCommit(url1
);
4175 NavigateAndCommit(url2
);
4176 NavigateAndCommit(url3
);
4177 controller
.GoBack();
4178 contents()->CommitPendingNavigation();
4180 contents()->ExpectSetHistoryOffsetAndLength(0, 1);
4182 controller
.PruneAllButLastCommitted();
4184 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
4185 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url2
);
4188 // Test call to PruneAllButLastCommitted for a pending entry that is not yet in
4189 // the list of entries.
4190 TEST_F(NavigationControllerTest
, PruneAllButLastCommittedForPendingNotInList
) {
4191 NavigationControllerImpl
& controller
= controller_impl();
4192 const GURL
url1("http://foo/1");
4193 const GURL
url2("http://foo/2");
4194 const GURL
url3("http://foo/3");
4196 NavigateAndCommit(url1
);
4197 NavigateAndCommit(url2
);
4199 // Create a pending entry that is not in the entry list.
4201 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
4202 EXPECT_TRUE(controller
.GetPendingEntry());
4203 EXPECT_EQ(2, controller
.GetEntryCount());
4205 contents()->ExpectSetHistoryOffsetAndLength(0, 1);
4206 controller
.PruneAllButLastCommitted();
4208 // We should only have the last committed and pending entries at this point,
4209 // and the pending entry should still not be in the entry list.
4210 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
4211 EXPECT_EQ(url2
, controller
.GetEntryAtIndex(0)->GetURL());
4212 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
4213 EXPECT_TRUE(controller
.GetPendingEntry());
4214 EXPECT_EQ(1, controller
.GetEntryCount());
4216 // Try to commit the pending entry.
4217 main_test_rfh()->PrepareForCommit();
4218 main_test_rfh()->SendNavigate(2, url3
);
4219 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
4220 EXPECT_FALSE(controller
.GetPendingEntry());
4221 EXPECT_EQ(2, controller
.GetEntryCount());
4222 EXPECT_EQ(url3
, controller
.GetEntryAtIndex(1)->GetURL());
4225 // Test to ensure that when we do a history navigation back to the current
4226 // committed page (e.g., going forward to a slow-loading page, then pressing
4227 // the back button), we just stop the navigation to prevent the throbber from
4228 // running continuously. Otherwise, the RenderViewHost forces the throbber to
4229 // start, but WebKit essentially ignores the navigation and never sends a
4230 // message to stop the throbber.
4231 TEST_F(NavigationControllerTest
, StopOnHistoryNavigationToCurrentPage
) {
4232 NavigationControllerImpl
& controller
= controller_impl();
4233 const GURL
url0("http://foo/0");
4234 const GURL
url1("http://foo/1");
4236 NavigateAndCommit(url0
);
4237 NavigateAndCommit(url1
);
4239 // Go back to the original page, then forward to the slow page, then back
4240 controller
.GoBack();
4241 contents()->CommitPendingNavigation();
4243 controller
.GoForward();
4244 EXPECT_EQ(1, controller
.GetPendingEntryIndex());
4246 controller
.GoBack();
4247 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
4250 TEST_F(NavigationControllerTest
, IsInitialNavigation
) {
4251 NavigationControllerImpl
& controller
= controller_impl();
4252 TestNotificationTracker notifications
;
4253 RegisterForAllNavNotifications(¬ifications
, &controller
);
4256 EXPECT_TRUE(controller
.IsInitialNavigation());
4258 // After commit, it stays false.
4259 const GURL
url1("http://foo1");
4260 main_test_rfh()->NavigateAndCommitRendererInitiated(0, url1
);
4261 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
4262 navigation_entry_committed_counter_
= 0;
4263 EXPECT_FALSE(controller
.IsInitialNavigation());
4265 // After starting a new navigation, it stays false.
4266 const GURL
url2("http://foo2");
4268 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
4271 // Check that the favicon is not reused across a client redirect.
4272 // (crbug.com/28515)
4273 TEST_F(NavigationControllerTest
, ClearFaviconOnRedirect
) {
4274 const GURL
kPageWithFavicon("http://withfavicon.html");
4275 const GURL
kPageWithoutFavicon("http://withoutfavicon.html");
4276 const GURL
kIconURL("http://withfavicon.ico");
4277 const gfx::Image kDefaultFavicon
= FaviconStatus().image
;
4279 NavigationControllerImpl
& controller
= controller_impl();
4280 TestNotificationTracker notifications
;
4281 RegisterForAllNavNotifications(¬ifications
, &controller
);
4283 main_test_rfh()->NavigateAndCommitRendererInitiated(0, kPageWithFavicon
);
4284 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
4285 navigation_entry_committed_counter_
= 0;
4287 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
4289 EXPECT_EQ(kPageWithFavicon
, entry
->GetURL());
4291 // Simulate Chromium having set the favicon for |kPageWithFavicon|.
4292 content::FaviconStatus
& favicon_status
= entry
->GetFavicon();
4293 favicon_status
.image
= CreateImage(SK_ColorWHITE
);
4294 favicon_status
.url
= kIconURL
;
4295 favicon_status
.valid
= true;
4296 EXPECT_FALSE(DoImagesMatch(kDefaultFavicon
, entry
->GetFavicon().image
));
4298 main_test_rfh()->SendRendererInitiatedNavigationRequest(kPageWithoutFavicon
,
4300 main_test_rfh()->PrepareForCommit();
4301 main_test_rfh()->SendNavigateWithTransition(
4303 kPageWithoutFavicon
,
4304 ui::PAGE_TRANSITION_CLIENT_REDIRECT
);
4305 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
4306 navigation_entry_committed_counter_
= 0;
4308 entry
= controller
.GetLastCommittedEntry();
4310 EXPECT_EQ(kPageWithoutFavicon
, entry
->GetURL());
4312 EXPECT_TRUE(DoImagesMatch(kDefaultFavicon
, entry
->GetFavicon().image
));
4315 // Check that the favicon is not cleared for NavigationEntries which were
4316 // previously navigated to.
4317 TEST_F(NavigationControllerTest
, BackNavigationDoesNotClearFavicon
) {
4318 const GURL
kUrl1("http://www.a.com/1");
4319 const GURL
kUrl2("http://www.a.com/2");
4320 const GURL
kIconURL("http://www.a.com/1/favicon.ico");
4322 NavigationControllerImpl
& controller
= controller_impl();
4323 TestNotificationTracker notifications
;
4324 RegisterForAllNavNotifications(¬ifications
, &controller
);
4326 main_test_rfh()->NavigateAndCommitRendererInitiated(0, kUrl1
);
4327 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
4328 navigation_entry_committed_counter_
= 0;
4330 // Simulate Chromium having set the favicon for |kUrl1|.
4331 gfx::Image favicon_image
= CreateImage(SK_ColorWHITE
);
4332 content::NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
4334 content::FaviconStatus
& favicon_status
= entry
->GetFavicon();
4335 favicon_status
.image
= favicon_image
;
4336 favicon_status
.url
= kIconURL
;
4337 favicon_status
.valid
= true;
4339 // Navigate to another page and go back to the original page.
4340 main_test_rfh()->NavigateAndCommitRendererInitiated(1, kUrl2
);
4341 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
4342 navigation_entry_committed_counter_
= 0;
4343 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1
, false);
4344 main_test_rfh()->PrepareForCommit();
4345 main_test_rfh()->SendNavigateWithTransition(
4348 ui::PAGE_TRANSITION_FORWARD_BACK
);
4349 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
4350 navigation_entry_committed_counter_
= 0;
4352 // Verify that the favicon for the page at |kUrl1| was not cleared.
4353 entry
= controller
.GetEntryAtIndex(0);
4355 EXPECT_EQ(kUrl1
, entry
->GetURL());
4356 EXPECT_TRUE(DoImagesMatch(favicon_image
, entry
->GetFavicon().image
));
4359 // The test crashes on android: http://crbug.com/170449
4360 #if defined(OS_ANDROID)
4361 #define MAYBE_PurgeScreenshot DISABLED_PurgeScreenshot
4363 #define MAYBE_PurgeScreenshot PurgeScreenshot
4365 // Tests that screenshot are purged correctly.
4366 TEST_F(NavigationControllerTest
, MAYBE_PurgeScreenshot
) {
4367 NavigationControllerImpl
& controller
= controller_impl();
4369 NavigationEntryImpl
* entry
;
4371 // Navigate enough times to make sure that some screenshots are purged.
4372 for (int i
= 0; i
< 12; ++i
) {
4373 const GURL
url(base::StringPrintf("http://foo%d/", i
));
4374 NavigateAndCommit(url
);
4375 EXPECT_EQ(i
, controller
.GetCurrentEntryIndex());
4378 MockScreenshotManager
* screenshot_manager
=
4379 new MockScreenshotManager(&controller
);
4380 controller
.SetScreenshotManager(screenshot_manager
);
4381 for (int i
= 0; i
< controller
.GetEntryCount(); ++i
) {
4382 entry
= controller
.GetEntryAtIndex(i
);
4383 screenshot_manager
->TakeScreenshotFor(entry
);
4384 EXPECT_TRUE(entry
->screenshot().get());
4387 NavigateAndCommit(GURL("https://foo/"));
4388 EXPECT_EQ(13, controller
.GetEntryCount());
4389 entry
= controller
.GetEntryAtIndex(11);
4390 screenshot_manager
->TakeScreenshotFor(entry
);
4392 for (int i
= 0; i
< 2; ++i
) {
4393 entry
= controller
.GetEntryAtIndex(i
);
4394 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
4398 for (int i
= 2; i
< controller
.GetEntryCount() - 1; ++i
) {
4399 entry
= controller
.GetEntryAtIndex(i
);
4400 EXPECT_TRUE(entry
->screenshot().get()) << "Screenshot not found for " << i
;
4403 // Navigate to index 5 and then try to assign screenshot to all entries.
4404 controller
.GoToIndex(5);
4405 contents()->CommitPendingNavigation();
4406 EXPECT_EQ(5, controller
.GetCurrentEntryIndex());
4407 for (int i
= 0; i
< controller
.GetEntryCount() - 1; ++i
) {
4408 entry
= controller
.GetEntryAtIndex(i
);
4409 screenshot_manager
->TakeScreenshotFor(entry
);
4412 for (int i
= 10; i
<= 12; ++i
) {
4413 entry
= controller
.GetEntryAtIndex(i
);
4414 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
4416 screenshot_manager
->TakeScreenshotFor(entry
);
4419 // Navigate to index 7 and assign screenshot to all entries.
4420 controller
.GoToIndex(7);
4421 contents()->CommitPendingNavigation();
4422 EXPECT_EQ(7, controller
.GetCurrentEntryIndex());
4423 for (int i
= 0; i
< controller
.GetEntryCount() - 1; ++i
) {
4424 entry
= controller
.GetEntryAtIndex(i
);
4425 screenshot_manager
->TakeScreenshotFor(entry
);
4428 for (int i
= 0; i
< 2; ++i
) {
4429 entry
= controller
.GetEntryAtIndex(i
);
4430 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
4434 // Clear all screenshots.
4435 EXPECT_EQ(13, controller
.GetEntryCount());
4436 EXPECT_EQ(10, screenshot_manager
->GetScreenshotCount());
4437 controller
.ClearAllScreenshots();
4438 EXPECT_EQ(0, screenshot_manager
->GetScreenshotCount());
4439 for (int i
= 0; i
< controller
.GetEntryCount(); ++i
) {
4440 entry
= controller
.GetEntryAtIndex(i
);
4441 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
4446 TEST_F(NavigationControllerTest
, PushStateUpdatesTitleAndFavicon
) {
4448 main_test_rfh()->NavigateAndCommitRendererInitiated(1, GURL("http://foo"));
4450 // Set title and favicon.
4451 base::string16
title(base::ASCIIToUTF16("Title"));
4452 FaviconStatus favicon
;
4453 favicon
.valid
= true;
4454 favicon
.url
= GURL("http://foo/favicon.ico");
4455 controller().GetLastCommittedEntry()->SetTitle(title
);
4456 controller().GetLastCommittedEntry()->GetFavicon() = favicon
;
4458 // history.pushState() is called.
4459 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
4460 GURL
kUrl2("http://foo#foo");
4463 params
.page_state
= PageState::CreateFromURL(kUrl2
);
4464 params
.was_within_same_page
= true;
4465 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, false);
4466 main_test_rfh()->PrepareForCommit();
4467 main_test_rfh()->SendNavigateWithParams(¶ms
);
4469 // The title should immediately be visible on the new NavigationEntry.
4470 base::string16 new_title
=
4471 controller().GetLastCommittedEntry()->GetTitleForDisplay(std::string());
4472 EXPECT_EQ(title
, new_title
);
4473 FaviconStatus new_favicon
=
4474 controller().GetLastCommittedEntry()->GetFavicon();
4475 EXPECT_EQ(favicon
.valid
, new_favicon
.valid
);
4476 EXPECT_EQ(favicon
.url
, new_favicon
.url
);
4479 // Test that the navigation controller clears its session history when a
4480 // navigation commits with the clear history list flag set.
4481 TEST_F(NavigationControllerTest
, ClearHistoryList
) {
4482 const GURL
url1("http://foo1");
4483 const GURL
url2("http://foo2");
4484 const GURL
url3("http://foo3");
4485 const GURL
url4("http://foo4");
4487 NavigationControllerImpl
& controller
= controller_impl();
4489 // Create a session history with three entries, second entry is active.
4490 NavigateAndCommit(url1
);
4491 NavigateAndCommit(url2
);
4492 NavigateAndCommit(url3
);
4493 controller
.GoBack();
4494 contents()->CommitPendingNavigation();
4495 EXPECT_EQ(3, controller
.GetEntryCount());
4496 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
4498 // Create a new pending navigation, and indicate that the session history
4499 // should be cleared.
4500 NavigationController::LoadURLParams
params(url4
);
4501 params
.should_clear_history_list
= true;
4502 controller
.LoadURLWithParams(params
);
4504 // Verify that the pending entry correctly indicates that the session history
4505 // should be cleared.
4506 NavigationEntryImpl
* entry
= controller
.GetPendingEntry();
4508 EXPECT_TRUE(entry
->should_clear_history_list());
4510 // Assume that the RenderFrame correctly cleared its history and commit the
4512 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
4513 switches::kEnableBrowserSideNavigation
)) {
4514 contents()->GetMainFrame()->SendBeforeUnloadACK(true);
4516 contents()->GetPendingMainFrame()->
4517 set_simulate_history_list_was_cleared(true);
4518 contents()->CommitPendingNavigation();
4520 // Verify that the NavigationController's session history was correctly
4522 EXPECT_EQ(1, controller
.GetEntryCount());
4523 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
4524 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
4525 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
4526 EXPECT_FALSE(controller
.CanGoBack());
4527 EXPECT_FALSE(controller
.CanGoForward());
4528 EXPECT_EQ(url4
, controller
.GetVisibleEntry()->GetURL());
4531 TEST_F(NavigationControllerTest
, PostThenReplaceStateThenReload
) {
4532 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
4533 EXPECT_FALSE(contents()->GetDelegate());
4534 contents()->SetDelegate(delegate
.get());
4537 GURL
url("http://foo");
4538 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
4541 params
.transition
= ui::PAGE_TRANSITION_FORM_SUBMIT
;
4542 params
.gesture
= NavigationGestureUser
;
4543 params
.page_state
= PageState::CreateFromURL(url
);
4544 params
.was_within_same_page
= false;
4545 params
.is_post
= true;
4547 main_test_rfh()->SendRendererInitiatedNavigationRequest(url
, false);
4548 main_test_rfh()->PrepareForCommit();
4549 contents()->GetMainFrame()->SendNavigateWithParams(¶ms
);
4551 // history.replaceState() is called.
4552 GURL
replace_url("http://foo#foo");
4554 params
.url
= replace_url
;
4555 params
.transition
= ui::PAGE_TRANSITION_LINK
;
4556 params
.gesture
= NavigationGestureUser
;
4557 params
.page_state
= PageState::CreateFromURL(replace_url
);
4558 params
.was_within_same_page
= true;
4559 params
.is_post
= false;
4560 params
.post_id
= -1;
4561 main_test_rfh()->SendRendererInitiatedNavigationRequest(replace_url
, false);
4562 main_test_rfh()->PrepareForCommit();
4563 contents()->GetMainFrame()->SendNavigateWithParams(¶ms
);
4565 // Now reload. replaceState overrides the POST, so we should not show a
4566 // repost warning dialog.
4567 controller_impl().Reload(true);
4568 EXPECT_EQ(0, delegate
->repost_form_warning_count());
4571 TEST_F(NavigationControllerTest
, UnreachableURLGivesErrorPage
) {
4572 GURL
url("http://foo");
4573 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
4576 params
.transition
= ui::PAGE_TRANSITION_LINK
;
4577 params
.gesture
= NavigationGestureUser
;
4578 params
.page_state
= PageState::CreateFromURL(url
);
4579 params
.was_within_same_page
= false;
4580 params
.is_post
= true;
4582 params
.url_is_unreachable
= true;
4583 // Navigate to new page
4585 LoadCommittedDetails details
;
4586 controller_impl().RendererDidNavigate(main_test_rfh(), params
, &details
);
4587 EXPECT_EQ(PAGE_TYPE_ERROR
,
4588 controller_impl().GetLastCommittedEntry()->GetPageType());
4589 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, details
.type
);
4592 // Navigate to existing page.
4594 LoadCommittedDetails details
;
4595 controller_impl().RendererDidNavigate(main_test_rfh(), params
, &details
);
4596 EXPECT_EQ(PAGE_TYPE_ERROR
,
4597 controller_impl().GetLastCommittedEntry()->GetPageType());
4598 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, details
.type
);
4601 // Navigate to same page.
4602 // Note: The call to LoadURL() creates a pending entry in order to trigger the
4603 // same-page transition.
4604 controller_impl().LoadURL(
4605 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
4606 params
.transition
= ui::PAGE_TRANSITION_TYPED
;
4608 LoadCommittedDetails details
;
4609 controller_impl().RendererDidNavigate(main_test_rfh(), params
, &details
);
4610 EXPECT_EQ(PAGE_TYPE_ERROR
,
4611 controller_impl().GetLastCommittedEntry()->GetPageType());
4612 EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE
, details
.type
);
4615 // Navigate in page.
4616 params
.url
= GURL("http://foo#foo");
4617 params
.transition
= ui::PAGE_TRANSITION_LINK
;
4618 params
.was_within_same_page
= true;
4620 LoadCommittedDetails details
;
4621 controller_impl().RendererDidNavigate(main_test_rfh(), params
, &details
);
4622 EXPECT_EQ(PAGE_TYPE_ERROR
,
4623 controller_impl().GetLastCommittedEntry()->GetPageType());
4624 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE
, details
.type
);
4628 } // namespace content