1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/basictypes.h"
7 #include "base/file_util.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/path_service.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h"
14 #include "content/browser/frame_host/navigation_controller_impl.h"
15 #include "content/browser/frame_host/navigation_entry_impl.h"
16 #include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
17 #include "content/browser/frame_host/navigator.h"
18 #include "content/browser/site_instance_impl.h"
19 #include "content/browser/web_contents/web_contents_impl.h"
20 #include "content/common/frame_messages.h"
21 #include "content/common/view_messages.h"
22 #include "content/public/browser/navigation_details.h"
23 #include "content/public/browser/notification_registrar.h"
24 #include "content/public/browser/notification_types.h"
25 #include "content/public/browser/render_view_host.h"
26 #include "content/public/browser/web_contents_delegate.h"
27 #include "content/public/browser/web_contents_observer.h"
28 #include "content/public/common/page_state.h"
29 #include "content/public/common/url_constants.h"
30 #include "content/public/test/mock_render_process_host.h"
31 #include "content/public/test/test_notification_tracker.h"
32 #include "content/public/test/test_utils.h"
33 #include "content/test/test_render_view_host.h"
34 #include "content/test/test_web_contents.h"
35 #include "net/base/net_util.h"
36 #include "skia/ext/platform_canvas.h"
37 #include "testing/gtest/include/gtest/gtest.h"
43 // Creates an image with a 1x1 SkBitmap of the specified |color|.
44 gfx::Image
CreateImage(SkColor color
) {
46 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 1, 1);
48 bitmap
.eraseColor(color
);
49 return gfx::Image::CreateFrom1xBitmap(bitmap
);
52 // Returns true if images |a| and |b| have the same pixel data.
53 bool DoImagesMatch(const gfx::Image
& a
, const gfx::Image
& b
) {
54 // Assume that if the 1x bitmaps match, the images match.
55 SkBitmap a_bitmap
= a
.AsBitmap();
56 SkBitmap b_bitmap
= b
.AsBitmap();
58 if (a_bitmap
.width() != b_bitmap
.width() ||
59 a_bitmap
.height() != b_bitmap
.height()) {
62 SkAutoLockPixels
a_bitmap_lock(a_bitmap
);
63 SkAutoLockPixels
b_bitmap_lock(b_bitmap
);
64 return memcmp(a_bitmap
.getPixels(),
66 a_bitmap
.getSize()) == 0;
69 class MockScreenshotManager
: public content::NavigationEntryScreenshotManager
{
71 explicit MockScreenshotManager(content::NavigationControllerImpl
* owner
)
72 : content::NavigationEntryScreenshotManager(owner
),
73 encoding_screenshot_in_progress_(false) {
76 virtual ~MockScreenshotManager() {
79 void TakeScreenshotFor(content::NavigationEntryImpl
* entry
) {
81 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 1, 1);
83 bitmap
.eraseRGB(0, 0, 0);
84 encoding_screenshot_in_progress_
= true;
85 OnScreenshotTaken(entry
->GetUniqueID(), true, bitmap
);
86 WaitUntilScreenshotIsReady();
89 int GetScreenshotCount() {
90 return content::NavigationEntryScreenshotManager::GetScreenshotCount();
93 void WaitUntilScreenshotIsReady() {
94 if (!encoding_screenshot_in_progress_
)
96 message_loop_runner_
= new content::MessageLoopRunner
;
97 message_loop_runner_
->Run();
101 // Overridden from content::NavigationEntryScreenshotManager:
102 virtual void TakeScreenshotImpl(
103 content::RenderViewHost
* host
,
104 content::NavigationEntryImpl
* entry
) OVERRIDE
{
107 virtual void OnScreenshotSet(content::NavigationEntryImpl
* entry
) OVERRIDE
{
108 encoding_screenshot_in_progress_
= false;
109 NavigationEntryScreenshotManager::OnScreenshotSet(entry
);
110 if (message_loop_runner_
.get())
111 message_loop_runner_
->Quit();
114 scoped_refptr
<content::MessageLoopRunner
> message_loop_runner_
;
115 bool encoding_screenshot_in_progress_
;
117 DISALLOW_COPY_AND_ASSIGN(MockScreenshotManager
);
124 // TimeSmoother tests ----------------------------------------------------------
126 // With no duplicates, GetSmoothedTime should be the identity
128 TEST(TimeSmoother
, Basic
) {
129 NavigationControllerImpl::TimeSmoother smoother
;
130 for (int64 i
= 1; i
< 1000; ++i
) {
131 base::Time t
= base::Time::FromInternalValue(i
);
132 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
136 // With a single duplicate and timestamps thereafter increasing by one
137 // microsecond, the smoothed time should always be one behind.
138 TEST(TimeSmoother
, SingleDuplicate
) {
139 NavigationControllerImpl::TimeSmoother smoother
;
140 base::Time t
= base::Time::FromInternalValue(1);
141 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
142 for (int64 i
= 1; i
< 1000; ++i
) {
143 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1);
144 t
= base::Time::FromInternalValue(i
);
145 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
149 // With k duplicates and timestamps thereafter increasing by one
150 // microsecond, the smoothed time should always be k behind.
151 TEST(TimeSmoother
, ManyDuplicates
) {
152 const int64 kNumDuplicates
= 100;
153 NavigationControllerImpl::TimeSmoother smoother
;
154 base::Time t
= base::Time::FromInternalValue(1);
155 for (int64 i
= 0; i
< kNumDuplicates
; ++i
) {
156 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1);
157 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
159 for (int64 i
= 1; i
< 1000; ++i
) {
160 base::Time expected_t
=
161 base::Time::FromInternalValue(i
+ kNumDuplicates
);
162 t
= base::Time::FromInternalValue(i
);
163 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
167 // If the clock jumps far back enough after a run of duplicates, it
168 // should immediately jump to that value.
169 TEST(TimeSmoother
, ClockBackwardsJump
) {
170 const int64 kNumDuplicates
= 100;
171 NavigationControllerImpl::TimeSmoother smoother
;
172 base::Time t
= base::Time::FromInternalValue(1000);
173 for (int64 i
= 0; i
< kNumDuplicates
; ++i
) {
174 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1000);
175 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
177 t
= base::Time::FromInternalValue(500);
178 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
181 // NavigationControllerTest ----------------------------------------------------
183 class NavigationControllerTest
184 : public RenderViewHostImplTestHarness
,
185 public WebContentsObserver
{
187 NavigationControllerTest() : navigation_entry_committed_counter_(0) {
190 virtual void SetUp() OVERRIDE
{
191 RenderViewHostImplTestHarness::SetUp();
192 WebContents
* web_contents
= RenderViewHostImplTestHarness::web_contents();
193 ASSERT_TRUE(web_contents
); // The WebContents should be created by now.
194 WebContentsObserver::Observe(web_contents
);
197 // WebContentsObserver:
198 virtual void DidStartNavigationToPendingEntry(
200 NavigationController::ReloadType reload_type
) OVERRIDE
{
201 navigated_url_
= url
;
204 virtual void NavigationEntryCommitted(
205 const LoadCommittedDetails
& load_details
) OVERRIDE
{
206 navigation_entry_committed_counter_
++;
209 const GURL
& navigated_url() const {
210 return navigated_url_
;
213 NavigationControllerImpl
& controller_impl() {
214 return static_cast<NavigationControllerImpl
&>(controller());
219 size_t navigation_entry_committed_counter_
;
222 void RegisterForAllNavNotifications(TestNotificationTracker
* tracker
,
223 NavigationController
* controller
) {
224 tracker
->ListenFor(NOTIFICATION_NAV_LIST_PRUNED
,
225 Source
<NavigationController
>(controller
));
226 tracker
->ListenFor(NOTIFICATION_NAV_ENTRY_CHANGED
,
227 Source
<NavigationController
>(controller
));
230 SiteInstance
* GetSiteInstanceFromEntry(NavigationEntry
* entry
) {
231 return NavigationEntryImpl::FromNavigationEntry(entry
)->site_instance();
234 class TestWebContentsDelegate
: public WebContentsDelegate
{
236 explicit TestWebContentsDelegate() :
237 navigation_state_change_count_(0) {}
239 int navigation_state_change_count() {
240 return navigation_state_change_count_
;
243 // Keep track of whether the tab has notified us of a navigation state change.
244 virtual void NavigationStateChanged(const WebContents
* source
,
245 unsigned changed_flags
) OVERRIDE
{
246 navigation_state_change_count_
++;
250 // The number of times NavigationStateChanged has been called.
251 int navigation_state_change_count_
;
254 // -----------------------------------------------------------------------------
256 TEST_F(NavigationControllerTest
, Defaults
) {
257 NavigationControllerImpl
& controller
= controller_impl();
259 EXPECT_FALSE(controller
.GetPendingEntry());
260 EXPECT_FALSE(controller
.GetVisibleEntry());
261 EXPECT_FALSE(controller
.GetLastCommittedEntry());
262 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
263 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), -1);
264 EXPECT_EQ(controller
.GetEntryCount(), 0);
265 EXPECT_FALSE(controller
.CanGoBack());
266 EXPECT_FALSE(controller
.CanGoForward());
269 TEST_F(NavigationControllerTest
, GoToOffset
) {
270 NavigationControllerImpl
& controller
= controller_impl();
271 TestNotificationTracker notifications
;
272 RegisterForAllNavNotifications(¬ifications
, &controller
);
274 const int kNumUrls
= 5;
275 std::vector
<GURL
> urls(kNumUrls
);
276 for (int i
= 0; i
< kNumUrls
; ++i
) {
277 urls
[i
] = GURL(base::StringPrintf("http://www.a.com/%d", i
));
280 test_rvh()->SendNavigate(0, urls
[0]);
281 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
282 navigation_entry_committed_counter_
= 0;
283 EXPECT_EQ(urls
[0], controller
.GetVisibleEntry()->GetVirtualURL());
284 EXPECT_FALSE(controller
.CanGoBack());
285 EXPECT_FALSE(controller
.CanGoForward());
286 EXPECT_FALSE(controller
.CanGoToOffset(1));
288 for (int i
= 1; i
<= 4; ++i
) {
289 test_rvh()->SendNavigate(i
, urls
[i
]);
290 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
291 navigation_entry_committed_counter_
= 0;
292 EXPECT_EQ(urls
[i
], controller
.GetVisibleEntry()->GetVirtualURL());
293 EXPECT_TRUE(controller
.CanGoToOffset(-i
));
294 EXPECT_FALSE(controller
.CanGoToOffset(-(i
+ 1)));
295 EXPECT_FALSE(controller
.CanGoToOffset(1));
298 // We have loaded 5 pages, and are currently at the last-loaded page.
302 GO_TO_MIDDLE_PAGE
= -2,
305 GO_TO_BEGINNING
= -2,
310 const int test_offsets
[NUM_TESTS
] = {
318 for (int test
= 0; test
< NUM_TESTS
; ++test
) {
319 int offset
= test_offsets
[test
];
320 controller
.GoToOffset(offset
);
322 // Check that the GoToOffset will land on the expected page.
323 EXPECT_EQ(urls
[url_index
], controller
.GetPendingEntry()->GetVirtualURL());
324 test_rvh()->SendNavigate(url_index
, urls
[url_index
]);
325 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
326 navigation_entry_committed_counter_
= 0;
327 // Check that we can go to any valid offset into the history.
328 for (size_t j
= 0; j
< urls
.size(); ++j
)
329 EXPECT_TRUE(controller
.CanGoToOffset(j
- url_index
));
330 // Check that we can't go beyond the beginning or end of the history.
331 EXPECT_FALSE(controller
.CanGoToOffset(-(url_index
+ 1)));
332 EXPECT_FALSE(controller
.CanGoToOffset(urls
.size() - url_index
));
336 TEST_F(NavigationControllerTest
, LoadURL
) {
337 NavigationControllerImpl
& controller
= controller_impl();
338 TestNotificationTracker notifications
;
339 RegisterForAllNavNotifications(¬ifications
, &controller
);
341 const GURL
url1("http://foo1");
342 const GURL
url2("http://foo2");
344 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
345 // Creating a pending notification should not have issued any of the
346 // notifications we're listening for.
347 EXPECT_EQ(0U, notifications
.size());
349 // The load should now be pending.
350 EXPECT_EQ(controller
.GetEntryCount(), 0);
351 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), -1);
352 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
353 EXPECT_FALSE(controller
.GetLastCommittedEntry());
354 ASSERT_TRUE(controller
.GetPendingEntry());
355 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetVisibleEntry());
356 EXPECT_FALSE(controller
.CanGoBack());
357 EXPECT_FALSE(controller
.CanGoForward());
358 EXPECT_EQ(contents()->GetMaxPageID(), -1);
360 // Neither the timestamp nor the status code should have been set yet.
361 EXPECT_TRUE(controller
.GetPendingEntry()->GetTimestamp().is_null());
362 EXPECT_EQ(0, controller
.GetPendingEntry()->GetHttpStatusCode());
364 // We should have gotten no notifications from the preceeding checks.
365 EXPECT_EQ(0U, notifications
.size());
367 test_rvh()->SendNavigate(0, url1
);
368 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
369 navigation_entry_committed_counter_
= 0;
371 // The load should now be committed.
372 EXPECT_EQ(controller
.GetEntryCount(), 1);
373 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
374 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
375 EXPECT_TRUE(controller
.GetLastCommittedEntry());
376 EXPECT_FALSE(controller
.GetPendingEntry());
377 ASSERT_TRUE(controller
.GetVisibleEntry());
378 EXPECT_FALSE(controller
.CanGoBack());
379 EXPECT_FALSE(controller
.CanGoForward());
380 EXPECT_EQ(contents()->GetMaxPageID(), 0);
381 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
382 controller
.GetLastCommittedEntry())->bindings());
384 // The timestamp should have been set.
385 EXPECT_FALSE(controller
.GetVisibleEntry()->GetTimestamp().is_null());
388 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
390 // The load should now be pending.
391 EXPECT_EQ(controller
.GetEntryCount(), 1);
392 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
393 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
394 EXPECT_TRUE(controller
.GetLastCommittedEntry());
395 ASSERT_TRUE(controller
.GetPendingEntry());
396 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetVisibleEntry());
397 // TODO(darin): maybe this should really be true?
398 EXPECT_FALSE(controller
.CanGoBack());
399 EXPECT_FALSE(controller
.CanGoForward());
400 EXPECT_EQ(contents()->GetMaxPageID(), 0);
402 EXPECT_TRUE(controller
.GetPendingEntry()->GetTimestamp().is_null());
404 // Simulate the beforeunload ack for the cross-site transition, and then the
406 test_rvh()->SendShouldCloseACK(true);
407 static_cast<TestRenderViewHost
*>(
408 contents()->GetPendingRenderViewHost())->SendNavigate(1, url2
);
409 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
410 navigation_entry_committed_counter_
= 0;
412 // The load should now be committed.
413 EXPECT_EQ(controller
.GetEntryCount(), 2);
414 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
415 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
416 EXPECT_TRUE(controller
.GetLastCommittedEntry());
417 EXPECT_FALSE(controller
.GetPendingEntry());
418 ASSERT_TRUE(controller
.GetVisibleEntry());
419 EXPECT_TRUE(controller
.CanGoBack());
420 EXPECT_FALSE(controller
.CanGoForward());
421 EXPECT_EQ(contents()->GetMaxPageID(), 1);
423 EXPECT_FALSE(controller
.GetVisibleEntry()->GetTimestamp().is_null());
428 base::Time
GetFixedTime(base::Time time
) {
434 TEST_F(NavigationControllerTest
, LoadURLSameTime
) {
435 NavigationControllerImpl
& controller
= controller_impl();
436 TestNotificationTracker notifications
;
437 RegisterForAllNavNotifications(¬ifications
, &controller
);
439 // Set the clock to always return a timestamp of 1.
440 controller
.SetGetTimestampCallbackForTest(
441 base::Bind(&GetFixedTime
, base::Time::FromInternalValue(1)));
443 const GURL
url1("http://foo1");
444 const GURL
url2("http://foo2");
446 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
448 test_rvh()->SendNavigate(0, url1
);
449 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
450 navigation_entry_committed_counter_
= 0;
453 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
455 // Simulate the beforeunload ack for the cross-site transition, and then the
457 test_rvh()->SendShouldCloseACK(true);
458 test_rvh()->SendNavigate(1, url2
);
459 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
460 navigation_entry_committed_counter_
= 0;
462 // The two loads should now be committed.
463 ASSERT_EQ(controller
.GetEntryCount(), 2);
465 // Timestamps should be distinct despite the clock returning the
468 controller
.GetEntryAtIndex(0)->GetTimestamp().ToInternalValue());
470 controller
.GetEntryAtIndex(1)->GetTimestamp().ToInternalValue());
473 void CheckNavigationEntryMatchLoadParams(
474 NavigationController::LoadURLParams
& load_params
,
475 NavigationEntryImpl
* entry
) {
476 EXPECT_EQ(load_params
.url
, entry
->GetURL());
477 EXPECT_EQ(load_params
.referrer
.url
, entry
->GetReferrer().url
);
478 EXPECT_EQ(load_params
.referrer
.policy
, entry
->GetReferrer().policy
);
479 EXPECT_EQ(load_params
.transition_type
, entry
->GetTransitionType());
480 EXPECT_EQ(load_params
.extra_headers
, entry
->extra_headers());
482 EXPECT_EQ(load_params
.is_renderer_initiated
, entry
->is_renderer_initiated());
483 EXPECT_EQ(load_params
.base_url_for_data_url
, entry
->GetBaseURLForDataURL());
484 if (!load_params
.virtual_url_for_data_url
.is_empty()) {
485 EXPECT_EQ(load_params
.virtual_url_for_data_url
, entry
->GetVirtualURL());
487 if (NavigationController::UA_OVERRIDE_INHERIT
!=
488 load_params
.override_user_agent
) {
489 bool should_override
= (NavigationController::UA_OVERRIDE_TRUE
==
490 load_params
.override_user_agent
);
491 EXPECT_EQ(should_override
, entry
->GetIsOverridingUserAgent());
493 EXPECT_EQ(load_params
.browser_initiated_post_data
,
494 entry
->GetBrowserInitiatedPostData());
495 EXPECT_EQ(load_params
.transferred_global_request_id
,
496 entry
->transferred_global_request_id());
499 TEST_F(NavigationControllerTest
, LoadURLWithParams
) {
500 NavigationControllerImpl
& controller
= controller_impl();
502 NavigationController::LoadURLParams
load_params(GURL("http://foo"));
503 load_params
.referrer
=
504 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault
);
505 load_params
.transition_type
= PAGE_TRANSITION_GENERATED
;
506 load_params
.extra_headers
= "content-type: text/plain";
507 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
508 load_params
.is_renderer_initiated
= true;
509 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
510 load_params
.transferred_global_request_id
= GlobalRequestID(2, 3);
512 controller
.LoadURLWithParams(load_params
);
513 NavigationEntryImpl
* entry
=
514 NavigationEntryImpl::FromNavigationEntry(
515 controller
.GetPendingEntry());
517 // The timestamp should not have been set yet.
519 EXPECT_TRUE(entry
->GetTimestamp().is_null());
521 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
524 TEST_F(NavigationControllerTest
, LoadURLWithExtraParams_Data
) {
525 NavigationControllerImpl
& controller
= controller_impl();
527 NavigationController::LoadURLParams
load_params(
528 GURL("data:text/html,dataurl"));
529 load_params
.load_type
= NavigationController::LOAD_TYPE_DATA
;
530 load_params
.base_url_for_data_url
= GURL("http://foo");
531 load_params
.virtual_url_for_data_url
= GURL(kAboutBlankURL
);
532 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_FALSE
;
534 controller
.LoadURLWithParams(load_params
);
535 NavigationEntryImpl
* entry
=
536 NavigationEntryImpl::FromNavigationEntry(
537 controller
.GetPendingEntry());
539 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
542 TEST_F(NavigationControllerTest
, LoadURLWithExtraParams_HttpPost
) {
543 NavigationControllerImpl
& controller
= controller_impl();
545 NavigationController::LoadURLParams
load_params(GURL("https://posturl"));
546 load_params
.transition_type
= PAGE_TRANSITION_TYPED
;
547 load_params
.load_type
=
548 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST
;
549 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
552 const unsigned char* raw_data
=
553 reinterpret_cast<const unsigned char*>("d\n\0a2");
554 const int length
= 5;
555 std::vector
<unsigned char> post_data_vector(raw_data
, raw_data
+length
);
556 scoped_refptr
<base::RefCountedBytes
> data
=
557 base::RefCountedBytes::TakeVector(&post_data_vector
);
558 load_params
.browser_initiated_post_data
= data
.get();
560 controller
.LoadURLWithParams(load_params
);
561 NavigationEntryImpl
* entry
=
562 NavigationEntryImpl::FromNavigationEntry(
563 controller
.GetPendingEntry());
565 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
568 // Tests what happens when the same page is loaded again. Should not create a
569 // new session history entry. This is what happens when you press enter in the
570 // URL bar to reload: a pending entry is created and then it is discarded when
571 // the load commits (because WebCore didn't actually make a new entry).
572 TEST_F(NavigationControllerTest
, LoadURL_SamePage
) {
573 NavigationControllerImpl
& controller
= controller_impl();
574 TestNotificationTracker notifications
;
575 RegisterForAllNavNotifications(¬ifications
, &controller
);
577 const GURL
url1("http://foo1");
579 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
580 EXPECT_EQ(0U, notifications
.size());
581 test_rvh()->SendNavigate(0, url1
);
582 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
583 navigation_entry_committed_counter_
= 0;
585 ASSERT_TRUE(controller
.GetVisibleEntry());
586 const base::Time timestamp
= controller
.GetVisibleEntry()->GetTimestamp();
587 EXPECT_FALSE(timestamp
.is_null());
589 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
590 EXPECT_EQ(0U, notifications
.size());
591 test_rvh()->SendNavigate(0, url1
);
592 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
593 navigation_entry_committed_counter_
= 0;
595 // We should not have produced a new session history entry.
596 EXPECT_EQ(controller
.GetEntryCount(), 1);
597 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
598 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
599 EXPECT_TRUE(controller
.GetLastCommittedEntry());
600 EXPECT_FALSE(controller
.GetPendingEntry());
601 ASSERT_TRUE(controller
.GetVisibleEntry());
602 EXPECT_FALSE(controller
.CanGoBack());
603 EXPECT_FALSE(controller
.CanGoForward());
605 // The timestamp should have been updated.
607 // TODO(akalin): Change this EXPECT_GE (and other similar ones) to
608 // EXPECT_GT once we guarantee that timestamps are unique.
609 EXPECT_GE(controller
.GetVisibleEntry()->GetTimestamp(), timestamp
);
612 // Load the same page twice, once as a GET and once as a POST.
613 // We should update the post state on the NavigationEntry.
614 TEST_F(NavigationControllerTest
, LoadURL_SamePage_DifferentMethod
) {
615 NavigationControllerImpl
& controller
= controller_impl();
616 TestNotificationTracker notifications
;
617 RegisterForAllNavNotifications(¬ifications
, &controller
);
619 const GURL
url1("http://foo1");
621 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
622 ViewHostMsg_FrameNavigate_Params params
;
625 params
.transition
= PAGE_TRANSITION_TYPED
;
626 params
.is_post
= true;
627 params
.post_id
= 123;
628 params
.page_state
= PageState::CreateForTesting(url1
, false, 0, 0);
629 test_rvh()->SendNavigateWithParams(¶ms
);
631 // The post data should be visible.
632 NavigationEntry
* entry
= controller
.GetVisibleEntry();
634 EXPECT_TRUE(entry
->GetHasPostData());
635 EXPECT_EQ(entry
->GetPostID(), 123);
637 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
638 test_rvh()->SendNavigate(0, url1
);
640 // We should not have produced a new session history entry.
641 ASSERT_EQ(controller
.GetVisibleEntry(), entry
);
643 // The post data should have been cleared due to the GET.
644 EXPECT_FALSE(entry
->GetHasPostData());
645 EXPECT_EQ(entry
->GetPostID(), 0);
648 // Tests loading a URL but discarding it before the load commits.
649 TEST_F(NavigationControllerTest
, LoadURL_Discarded
) {
650 NavigationControllerImpl
& controller
= controller_impl();
651 TestNotificationTracker notifications
;
652 RegisterForAllNavNotifications(¬ifications
, &controller
);
654 const GURL
url1("http://foo1");
655 const GURL
url2("http://foo2");
657 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
658 EXPECT_EQ(0U, notifications
.size());
659 test_rvh()->SendNavigate(0, url1
);
660 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
661 navigation_entry_committed_counter_
= 0;
663 ASSERT_TRUE(controller
.GetVisibleEntry());
664 const base::Time timestamp
= controller
.GetVisibleEntry()->GetTimestamp();
665 EXPECT_FALSE(timestamp
.is_null());
667 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
668 controller
.DiscardNonCommittedEntries();
669 EXPECT_EQ(0U, notifications
.size());
671 // Should not have produced a new session history entry.
672 EXPECT_EQ(controller
.GetEntryCount(), 1);
673 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
674 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
675 EXPECT_TRUE(controller
.GetLastCommittedEntry());
676 EXPECT_FALSE(controller
.GetPendingEntry());
677 ASSERT_TRUE(controller
.GetVisibleEntry());
678 EXPECT_FALSE(controller
.CanGoBack());
679 EXPECT_FALSE(controller
.CanGoForward());
681 // Timestamp should not have changed.
682 EXPECT_EQ(timestamp
, controller
.GetVisibleEntry()->GetTimestamp());
685 // Tests navigations that come in unrequested. This happens when the user
686 // navigates from the web page, and here we test that there is no pending entry.
687 TEST_F(NavigationControllerTest
, LoadURL_NoPending
) {
688 NavigationControllerImpl
& controller
= controller_impl();
689 TestNotificationTracker notifications
;
690 RegisterForAllNavNotifications(¬ifications
, &controller
);
692 // First make an existing committed entry.
693 const GURL
kExistingURL1("http://eh");
695 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
696 test_rvh()->SendNavigate(0, kExistingURL1
);
697 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
698 navigation_entry_committed_counter_
= 0;
700 // Do a new navigation without making a pending one.
701 const GURL
kNewURL("http://see");
702 test_rvh()->SendNavigate(99, kNewURL
);
704 // There should no longer be any pending entry, and the third navigation we
705 // just made should be committed.
706 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
707 navigation_entry_committed_counter_
= 0;
708 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
709 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
710 EXPECT_EQ(kNewURL
, controller
.GetVisibleEntry()->GetURL());
713 // Tests navigating to a new URL when there is a new pending navigation that is
714 // not the one that just loaded. This will happen if the user types in a URL to
715 // somewhere slow, and then navigates the current page before the typed URL
717 TEST_F(NavigationControllerTest
, LoadURL_NewPending
) {
718 NavigationControllerImpl
& controller
= controller_impl();
719 TestNotificationTracker notifications
;
720 RegisterForAllNavNotifications(¬ifications
, &controller
);
722 // First make an existing committed entry.
723 const GURL
kExistingURL1("http://eh");
725 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
726 test_rvh()->SendNavigate(0, kExistingURL1
);
727 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
728 navigation_entry_committed_counter_
= 0;
730 // Make a pending entry to somewhere new.
731 const GURL
kExistingURL2("http://bee");
733 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
734 EXPECT_EQ(0U, notifications
.size());
736 // After the beforeunload but before it commits, do a new navigation.
737 test_rvh()->SendShouldCloseACK(true);
738 const GURL
kNewURL("http://see");
739 static_cast<TestRenderViewHost
*>(
740 contents()->GetPendingRenderViewHost())->SendNavigate(3, kNewURL
);
742 // There should no longer be any pending entry, and the third navigation we
743 // just made should be committed.
744 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
745 navigation_entry_committed_counter_
= 0;
746 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
747 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
748 EXPECT_EQ(kNewURL
, controller
.GetVisibleEntry()->GetURL());
751 // Tests navigating to a new URL when there is a pending back/forward
752 // navigation. This will happen if the user hits back, but before that commits,
753 // they navigate somewhere new.
754 TEST_F(NavigationControllerTest
, LoadURL_ExistingPending
) {
755 NavigationControllerImpl
& controller
= controller_impl();
756 TestNotificationTracker notifications
;
757 RegisterForAllNavNotifications(¬ifications
, &controller
);
759 // First make some history.
760 const GURL
kExistingURL1("http://foo/eh");
762 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
763 test_rvh()->SendNavigate(0, kExistingURL1
);
764 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
765 navigation_entry_committed_counter_
= 0;
767 const GURL
kExistingURL2("http://foo/bee");
769 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
770 test_rvh()->SendNavigate(1, kExistingURL2
);
771 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
772 navigation_entry_committed_counter_
= 0;
774 // Now make a pending back/forward navigation. The zeroth entry should be
777 EXPECT_EQ(0U, notifications
.size());
778 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
779 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
781 // Before that commits, do a new navigation.
782 const GURL
kNewURL("http://foo/see");
783 LoadCommittedDetails details
;
784 test_rvh()->SendNavigate(3, kNewURL
);
786 // There should no longer be any pending entry, and the third navigation we
787 // just made should be committed.
788 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
789 navigation_entry_committed_counter_
= 0;
790 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
791 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
792 EXPECT_EQ(kNewURL
, controller
.GetVisibleEntry()->GetURL());
795 // Tests navigating to a new URL when there is a pending back/forward
796 // navigation to a cross-process, privileged URL. This will happen if the user
797 // hits back, but before that commits, they navigate somewhere new.
798 TEST_F(NavigationControllerTest
, LoadURL_PrivilegedPending
) {
799 NavigationControllerImpl
& controller
= controller_impl();
800 TestNotificationTracker notifications
;
801 RegisterForAllNavNotifications(¬ifications
, &controller
);
803 // First make some history, starting with a privileged URL.
804 const GURL
kExistingURL1("http://privileged");
806 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
807 // Pretend it has bindings so we can tell if we incorrectly copy it.
808 test_rvh()->AllowBindings(2);
809 test_rvh()->SendNavigate(0, kExistingURL1
);
810 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
811 navigation_entry_committed_counter_
= 0;
813 // Navigate cross-process to a second URL.
814 const GURL
kExistingURL2("http://foo/eh");
816 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
817 test_rvh()->SendShouldCloseACK(true);
818 TestRenderViewHost
* foo_rvh
= static_cast<TestRenderViewHost
*>(
819 contents()->GetPendingRenderViewHost());
820 foo_rvh
->SendNavigate(1, kExistingURL2
);
821 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
822 navigation_entry_committed_counter_
= 0;
824 // Now make a pending back/forward navigation to a privileged entry.
825 // The zeroth entry should be pending.
827 foo_rvh
->SendShouldCloseACK(true);
828 EXPECT_EQ(0U, notifications
.size());
829 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
830 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
831 EXPECT_EQ(2, NavigationEntryImpl::FromNavigationEntry(
832 controller
.GetPendingEntry())->bindings());
834 // Before that commits, do a new navigation.
835 const GURL
kNewURL("http://foo/bee");
836 LoadCommittedDetails details
;
837 foo_rvh
->SendNavigate(3, kNewURL
);
839 // There should no longer be any pending entry, and the third navigation we
840 // just made should be committed.
841 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
842 navigation_entry_committed_counter_
= 0;
843 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
844 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
845 EXPECT_EQ(kNewURL
, controller
.GetVisibleEntry()->GetURL());
846 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
847 controller
.GetLastCommittedEntry())->bindings());
850 // Tests navigating to an existing URL when there is a pending new navigation.
851 // This will happen if the user enters a URL, but before that commits, the
852 // current page fires history.back().
853 TEST_F(NavigationControllerTest
, LoadURL_BackPreemptsPending
) {
854 NavigationControllerImpl
& controller
= controller_impl();
855 TestNotificationTracker notifications
;
856 RegisterForAllNavNotifications(¬ifications
, &controller
);
858 // First make some history.
859 const GURL
kExistingURL1("http://foo/eh");
861 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
862 test_rvh()->SendNavigate(0, kExistingURL1
);
863 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
864 navigation_entry_committed_counter_
= 0;
866 const GURL
kExistingURL2("http://foo/bee");
868 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
869 test_rvh()->SendNavigate(1, kExistingURL2
);
870 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
871 navigation_entry_committed_counter_
= 0;
873 // Now make a pending new navigation.
874 const GURL
kNewURL("http://foo/see");
876 kNewURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
877 EXPECT_EQ(0U, notifications
.size());
878 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
879 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
881 // Before that commits, a back navigation from the renderer commits.
882 test_rvh()->SendNavigate(0, kExistingURL1
);
884 // There should no longer be any pending entry, and the back navigation we
885 // just made should be committed.
886 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
887 navigation_entry_committed_counter_
= 0;
888 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
889 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
890 EXPECT_EQ(kExistingURL1
, controller
.GetVisibleEntry()->GetURL());
893 // Tests an ignored navigation when there is a pending new navigation.
894 // This will happen if the user enters a URL, but before that commits, the
895 // current blank page reloads. See http://crbug.com/77507.
896 TEST_F(NavigationControllerTest
, LoadURL_IgnorePreemptsPending
) {
897 NavigationControllerImpl
& controller
= controller_impl();
898 TestNotificationTracker notifications
;
899 RegisterForAllNavNotifications(¬ifications
, &controller
);
901 // Set a WebContentsDelegate to listen for state changes.
902 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
903 EXPECT_FALSE(contents()->GetDelegate());
904 contents()->SetDelegate(delegate
.get());
906 // Without any navigations, the renderer starts at about:blank.
907 const GURL
kExistingURL(kAboutBlankURL
);
909 // Now make a pending new navigation.
910 const GURL
kNewURL("http://eh");
912 kNewURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
913 EXPECT_EQ(0U, notifications
.size());
914 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
915 EXPECT_TRUE(controller
.GetPendingEntry());
916 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
917 EXPECT_EQ(1, delegate
->navigation_state_change_count());
919 // Before that commits, a document.write and location.reload can cause the
920 // renderer to send a FrameNavigate with page_id -1.
921 test_rvh()->SendNavigate(-1, kExistingURL
);
923 // This should clear the pending entry and notify of a navigation state
924 // change, so that we do not keep displaying kNewURL.
925 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
926 EXPECT_FALSE(controller
.GetPendingEntry());
927 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
928 EXPECT_EQ(2, delegate
->navigation_state_change_count());
930 contents()->SetDelegate(NULL
);
933 // Tests that the pending entry state is correct after an abort.
934 // We do not want to clear the pending entry, so that the user doesn't
935 // lose a typed URL. (See http://crbug.com/9682.)
936 TEST_F(NavigationControllerTest
, LoadURL_AbortDoesntCancelPending
) {
937 NavigationControllerImpl
& controller
= controller_impl();
938 TestNotificationTracker notifications
;
939 RegisterForAllNavNotifications(¬ifications
, &controller
);
941 // Set a WebContentsDelegate to listen for state changes.
942 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
943 EXPECT_FALSE(contents()->GetDelegate());
944 contents()->SetDelegate(delegate
.get());
946 // Start with a pending new navigation.
947 const GURL
kNewURL("http://eh");
949 kNewURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
950 EXPECT_EQ(0U, notifications
.size());
951 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
952 EXPECT_TRUE(controller
.GetPendingEntry());
953 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
954 EXPECT_EQ(1, delegate
->navigation_state_change_count());
956 // It may abort before committing, if it's a download or due to a stop or
957 // a new navigation from the user.
958 FrameHostMsg_DidFailProvisionalLoadWithError_Params params
;
960 params
.is_main_frame
= true;
961 params
.error_code
= net::ERR_ABORTED
;
962 params
.error_description
= base::string16();
963 params
.url
= kNewURL
;
964 params
.showing_repost_interstitial
= false;
965 main_test_rfh()->OnMessageReceived(
966 FrameHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
969 // This should not clear the pending entry or notify of a navigation state
970 // change, so that we keep displaying kNewURL (until the user clears it).
971 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
972 EXPECT_TRUE(controller
.GetPendingEntry());
973 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
974 EXPECT_EQ(1, delegate
->navigation_state_change_count());
975 NavigationEntry
* pending_entry
= controller
.GetPendingEntry();
977 // Ensure that a reload keeps the same pending entry.
978 controller
.Reload(true);
979 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
980 EXPECT_TRUE(controller
.GetPendingEntry());
981 EXPECT_EQ(pending_entry
, controller
.GetPendingEntry());
982 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
984 contents()->SetDelegate(NULL
);
987 // Tests that the pending URL is not visible during a renderer-initiated
988 // redirect and abort. See http://crbug.com/83031.
989 TEST_F(NavigationControllerTest
, LoadURL_RedirectAbortDoesntShowPendingURL
) {
990 NavigationControllerImpl
& controller
= controller_impl();
991 TestNotificationTracker notifications
;
992 RegisterForAllNavNotifications(¬ifications
, &controller
);
994 // First make an existing committed entry.
995 const GURL
kExistingURL("http://foo/eh");
996 controller
.LoadURL(kExistingURL
, content::Referrer(),
997 content::PAGE_TRANSITION_TYPED
, std::string());
998 test_rvh()->SendNavigate(0, kExistingURL
);
999 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1000 navigation_entry_committed_counter_
= 0;
1002 // Set a WebContentsDelegate to listen for state changes.
1003 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
1004 EXPECT_FALSE(contents()->GetDelegate());
1005 contents()->SetDelegate(delegate
.get());
1007 // Now make a pending new navigation, initiated by the renderer.
1008 const GURL
kNewURL("http://foo/bee");
1009 NavigationController::LoadURLParams
load_url_params(kNewURL
);
1010 load_url_params
.transition_type
= PAGE_TRANSITION_TYPED
;
1011 load_url_params
.is_renderer_initiated
= true;
1012 controller
.LoadURLWithParams(load_url_params
);
1013 EXPECT_EQ(0U, notifications
.size());
1014 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1015 EXPECT_TRUE(controller
.GetPendingEntry());
1016 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1017 EXPECT_EQ(0, delegate
->navigation_state_change_count());
1019 // The visible entry should be the last committed URL, not the pending one.
1020 EXPECT_EQ(kExistingURL
, controller
.GetVisibleEntry()->GetURL());
1022 // Now the navigation redirects.
1023 const GURL
kRedirectURL("http://foo/see");
1024 test_rvh()->OnMessageReceived(
1025 ViewHostMsg_DidRedirectProvisionalLoad(0, // routing_id
1026 -1, // pending page_id
1028 kRedirectURL
)); // new url
1030 // We don't want to change the NavigationEntry's url, in case it cancels.
1031 // Prevents regression of http://crbug.com/77786.
1032 EXPECT_EQ(kNewURL
, controller
.GetPendingEntry()->GetURL());
1034 // It may abort before committing, if it's a download or due to a stop or
1035 // a new navigation from the user.
1036 FrameHostMsg_DidFailProvisionalLoadWithError_Params params
;
1037 params
.frame_id
= 1;
1038 params
.is_main_frame
= true;
1039 params
.error_code
= net::ERR_ABORTED
;
1040 params
.error_description
= base::string16();
1041 params
.url
= kRedirectURL
;
1042 params
.showing_repost_interstitial
= false;
1043 main_test_rfh()->OnMessageReceived(
1044 FrameHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
1047 // Because the pending entry is renderer initiated and not visible, we
1048 // clear it when it fails.
1049 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1050 EXPECT_FALSE(controller
.GetPendingEntry());
1051 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1052 EXPECT_EQ(0, delegate
->navigation_state_change_count());
1054 // The visible entry should be the last committed URL, not the pending one,
1055 // so that no spoof is possible.
1056 EXPECT_EQ(kExistingURL
, controller
.GetVisibleEntry()->GetURL());
1058 contents()->SetDelegate(NULL
);
1061 // Ensure that NavigationEntries track which bindings their RenderViewHost had
1062 // at the time they committed. http://crbug.com/173672.
1063 TEST_F(NavigationControllerTest
, LoadURL_WithBindings
) {
1064 NavigationControllerImpl
& controller
= controller_impl();
1065 TestNotificationTracker notifications
;
1066 RegisterForAllNavNotifications(¬ifications
, &controller
);
1068 const GURL
url1("http://foo1");
1069 const GURL
url2("http://foo2");
1071 // Navigate to a first, unprivileged URL.
1072 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1073 EXPECT_EQ(NavigationEntryImpl::kInvalidBindings
,
1074 NavigationEntryImpl::FromNavigationEntry(
1075 controller
.GetPendingEntry())->bindings());
1078 TestRenderViewHost
* orig_rvh
= static_cast<TestRenderViewHost
*>(test_rvh());
1079 orig_rvh
->SendNavigate(0, url1
);
1080 EXPECT_EQ(controller
.GetEntryCount(), 1);
1081 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1082 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
1083 controller
.GetLastCommittedEntry())->bindings());
1085 // Manually increase the number of active views in the SiteInstance
1086 // that orig_rvh belongs to, to prevent it from being destroyed when
1087 // it gets swapped out, so that we can reuse orig_rvh when the
1088 // controller goes back.
1089 static_cast<SiteInstanceImpl
*>(orig_rvh
->GetSiteInstance())->
1090 increment_active_view_count();
1092 // Navigate to a second URL, simulate the beforeunload ack for the cross-site
1093 // transition, and set bindings on the pending RenderViewHost to simulate a
1095 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1096 orig_rvh
->SendShouldCloseACK(true);
1097 contents()->GetPendingRenderViewHost()->AllowBindings(1);
1098 static_cast<TestRenderViewHost
*>(
1099 contents()->GetPendingRenderViewHost())->SendNavigate(1, url2
);
1101 // The second load should be committed, and bindings should be remembered.
1102 EXPECT_EQ(controller
.GetEntryCount(), 2);
1103 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1104 EXPECT_TRUE(controller
.CanGoBack());
1105 EXPECT_EQ(1, NavigationEntryImpl::FromNavigationEntry(
1106 controller
.GetLastCommittedEntry())->bindings());
1108 // Going back, the first entry should still appear unprivileged.
1109 controller
.GoBack();
1110 orig_rvh
->SendNavigate(0, url1
);
1111 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1112 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
1113 controller
.GetLastCommittedEntry())->bindings());
1116 TEST_F(NavigationControllerTest
, Reload
) {
1117 NavigationControllerImpl
& controller
= controller_impl();
1118 TestNotificationTracker notifications
;
1119 RegisterForAllNavNotifications(¬ifications
, &controller
);
1121 const GURL
url1("http://foo1");
1123 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1124 EXPECT_EQ(0U, notifications
.size());
1125 test_rvh()->SendNavigate(0, url1
);
1126 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1127 navigation_entry_committed_counter_
= 0;
1128 ASSERT_TRUE(controller
.GetVisibleEntry());
1129 controller
.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
1130 controller
.Reload(true);
1131 EXPECT_EQ(0U, notifications
.size());
1133 const base::Time timestamp
= controller
.GetVisibleEntry()->GetTimestamp();
1134 EXPECT_FALSE(timestamp
.is_null());
1136 // The reload is pending.
1137 EXPECT_EQ(controller
.GetEntryCount(), 1);
1138 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1139 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1140 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1141 EXPECT_TRUE(controller
.GetPendingEntry());
1142 EXPECT_FALSE(controller
.CanGoBack());
1143 EXPECT_FALSE(controller
.CanGoForward());
1144 // Make sure the title has been cleared (will be redrawn just after reload).
1145 // Avoids a stale cached title when the new page being reloaded has no title.
1146 // See http://crbug.com/96041.
1147 EXPECT_TRUE(controller
.GetVisibleEntry()->GetTitle().empty());
1149 test_rvh()->SendNavigate(0, url1
);
1150 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1151 navigation_entry_committed_counter_
= 0;
1153 // Now the reload is committed.
1154 EXPECT_EQ(controller
.GetEntryCount(), 1);
1155 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1156 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1157 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1158 EXPECT_FALSE(controller
.GetPendingEntry());
1159 EXPECT_FALSE(controller
.CanGoBack());
1160 EXPECT_FALSE(controller
.CanGoForward());
1162 // The timestamp should have been updated.
1163 ASSERT_TRUE(controller
.GetVisibleEntry());
1164 EXPECT_GE(controller
.GetVisibleEntry()->GetTimestamp(), timestamp
);
1167 // Tests what happens when a reload navigation produces a new page.
1168 TEST_F(NavigationControllerTest
, Reload_GeneratesNewPage
) {
1169 NavigationControllerImpl
& controller
= controller_impl();
1170 TestNotificationTracker notifications
;
1171 RegisterForAllNavNotifications(¬ifications
, &controller
);
1173 const GURL
url1("http://foo1");
1174 const GURL
url2("http://foo2");
1176 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1177 test_rvh()->SendNavigate(0, url1
);
1178 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1179 navigation_entry_committed_counter_
= 0;
1181 controller
.Reload(true);
1182 EXPECT_EQ(0U, notifications
.size());
1184 test_rvh()->SendNavigate(1, url2
);
1185 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1186 navigation_entry_committed_counter_
= 0;
1188 // Now the reload is committed.
1189 EXPECT_EQ(controller
.GetEntryCount(), 2);
1190 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1191 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1192 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1193 EXPECT_FALSE(controller
.GetPendingEntry());
1194 EXPECT_TRUE(controller
.CanGoBack());
1195 EXPECT_FALSE(controller
.CanGoForward());
1198 // This test ensures that when a guest renderer reloads, the reload goes through
1199 // without ending up in the "we have a wrong process for the URL" branch in
1200 // NavigationControllerImpl::ReloadInternal.
1201 TEST_F(NavigationControllerTest
, ReloadWithGuest
) {
1202 NavigationControllerImpl
& controller
= controller_impl();
1204 const GURL
url1("http://foo1");
1205 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1206 test_rvh()->SendNavigate(0, url1
);
1207 ASSERT_TRUE(controller
.GetVisibleEntry());
1209 // Make the entry believe its RenderProcessHost is a guest.
1210 NavigationEntryImpl
* entry1
=
1211 NavigationEntryImpl::FromNavigationEntry(controller
.GetVisibleEntry());
1212 reinterpret_cast<MockRenderProcessHost
*>(
1213 entry1
->site_instance()->GetProcess())->SetIsGuest(true);
1216 controller
.Reload(true);
1218 // The reload is pending. Check that the NavigationEntry didn't get replaced
1219 // because of having the wrong process.
1220 EXPECT_EQ(controller
.GetEntryCount(), 1);
1221 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1222 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1224 NavigationEntryImpl
* entry2
=
1225 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry());
1226 EXPECT_EQ(entry1
, entry2
);
1229 #if !defined(OS_ANDROID) // http://crbug.com/157428
1230 TEST_F(NavigationControllerTest
, ReloadOriginalRequestURL
) {
1231 NavigationControllerImpl
& controller
= controller_impl();
1232 TestNotificationTracker notifications
;
1233 RegisterForAllNavNotifications(¬ifications
, &controller
);
1235 const GURL
original_url("http://foo1");
1236 const GURL
final_url("http://foo2");
1238 // Load up the original URL, but get redirected.
1240 original_url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1241 EXPECT_EQ(0U, notifications
.size());
1242 test_rvh()->SendNavigateWithOriginalRequestURL(0, final_url
, original_url
);
1243 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1244 navigation_entry_committed_counter_
= 0;
1246 // The NavigationEntry should save both the original URL and the final
1249 original_url
, controller
.GetVisibleEntry()->GetOriginalRequestURL());
1250 EXPECT_EQ(final_url
, controller
.GetVisibleEntry()->GetURL());
1252 // Reload using the original URL.
1253 controller
.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
1254 controller
.ReloadOriginalRequestURL(false);
1255 EXPECT_EQ(0U, notifications
.size());
1257 // The reload is pending. The request should point to the original URL.
1258 EXPECT_EQ(original_url
, navigated_url());
1259 EXPECT_EQ(controller
.GetEntryCount(), 1);
1260 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1261 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1262 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1263 EXPECT_TRUE(controller
.GetPendingEntry());
1264 EXPECT_FALSE(controller
.CanGoBack());
1265 EXPECT_FALSE(controller
.CanGoForward());
1267 // Make sure the title has been cleared (will be redrawn just after reload).
1268 // Avoids a stale cached title when the new page being reloaded has no title.
1269 // See http://crbug.com/96041.
1270 EXPECT_TRUE(controller
.GetVisibleEntry()->GetTitle().empty());
1272 // Send that the navigation has proceeded; say it got redirected again.
1273 test_rvh()->SendNavigate(0, final_url
);
1274 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1275 navigation_entry_committed_counter_
= 0;
1277 // Now the reload is committed.
1278 EXPECT_EQ(controller
.GetEntryCount(), 1);
1279 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1280 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1281 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1282 EXPECT_FALSE(controller
.GetPendingEntry());
1283 EXPECT_FALSE(controller
.CanGoBack());
1284 EXPECT_FALSE(controller
.CanGoForward());
1287 #endif // !defined(OS_ANDROID)
1289 // Test that certain non-persisted NavigationEntryImpl values get reset after
1291 TEST_F(NavigationControllerTest
, ResetEntryValuesAfterCommit
) {
1292 NavigationControllerImpl
& controller
= controller_impl();
1293 const GURL
url1("http://foo1");
1294 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1296 // Set up some sample values.
1297 const unsigned char* raw_data
=
1298 reinterpret_cast<const unsigned char*>("post\n\n\0data");
1299 const int length
= 11;
1300 std::vector
<unsigned char> post_data_vector(raw_data
, raw_data
+length
);
1301 scoped_refptr
<base::RefCountedBytes
> post_data
=
1302 base::RefCountedBytes::TakeVector(&post_data_vector
);
1303 GlobalRequestID
transfer_id(3, 4);
1304 std::vector
<GURL
> redirects
;
1305 redirects
.push_back(GURL("http://foo2"));
1307 // Set non-persisted values on the pending entry.
1308 NavigationEntryImpl
* pending_entry
=
1309 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry());
1310 pending_entry
->SetBrowserInitiatedPostData(post_data
.get());
1311 pending_entry
->set_is_renderer_initiated(true);
1312 pending_entry
->set_transferred_global_request_id(transfer_id
);
1313 pending_entry
->set_should_replace_entry(true);
1314 pending_entry
->set_redirect_chain(redirects
);
1315 pending_entry
->set_should_clear_history_list(true);
1316 EXPECT_EQ(post_data
.get(), pending_entry
->GetBrowserInitiatedPostData());
1317 EXPECT_TRUE(pending_entry
->is_renderer_initiated());
1318 EXPECT_EQ(transfer_id
, pending_entry
->transferred_global_request_id());
1319 EXPECT_TRUE(pending_entry
->should_replace_entry());
1320 EXPECT_EQ(1U, pending_entry
->redirect_chain().size());
1321 EXPECT_TRUE(pending_entry
->should_clear_history_list());
1323 test_rvh()->SendNavigate(0, url1
);
1325 // Certain values that are only used for pending entries get reset after
1327 NavigationEntryImpl
* committed_entry
=
1328 NavigationEntryImpl::FromNavigationEntry(
1329 controller
.GetLastCommittedEntry());
1330 EXPECT_FALSE(committed_entry
->GetBrowserInitiatedPostData());
1331 EXPECT_FALSE(committed_entry
->is_renderer_initiated());
1332 EXPECT_EQ(GlobalRequestID(-1, -1),
1333 committed_entry
->transferred_global_request_id());
1334 EXPECT_FALSE(committed_entry
->should_replace_entry());
1335 EXPECT_EQ(0U, committed_entry
->redirect_chain().size());
1336 EXPECT_FALSE(committed_entry
->should_clear_history_list());
1339 // Tests what happens when we navigate back successfully
1340 TEST_F(NavigationControllerTest
, Back
) {
1341 NavigationControllerImpl
& controller
= controller_impl();
1342 TestNotificationTracker notifications
;
1343 RegisterForAllNavNotifications(¬ifications
, &controller
);
1345 const GURL
url1("http://foo1");
1346 test_rvh()->SendNavigate(0, url1
);
1347 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1348 navigation_entry_committed_counter_
= 0;
1350 const GURL
url2("http://foo2");
1351 test_rvh()->SendNavigate(1, url2
);
1352 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1353 navigation_entry_committed_counter_
= 0;
1355 controller
.GoBack();
1356 EXPECT_EQ(0U, notifications
.size());
1358 // We should now have a pending navigation to go back.
1359 EXPECT_EQ(controller
.GetEntryCount(), 2);
1360 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1361 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1362 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1363 EXPECT_TRUE(controller
.GetPendingEntry());
1364 EXPECT_FALSE(controller
.CanGoBack());
1365 EXPECT_FALSE(controller
.CanGoToOffset(-1));
1366 EXPECT_TRUE(controller
.CanGoForward());
1367 EXPECT_TRUE(controller
.CanGoToOffset(1));
1368 EXPECT_FALSE(controller
.CanGoToOffset(2)); // Cannot go foward 2 steps.
1370 // Timestamp for entry 1 should be on or after that of entry 0.
1371 EXPECT_FALSE(controller
.GetEntryAtIndex(0)->GetTimestamp().is_null());
1372 EXPECT_GE(controller
.GetEntryAtIndex(1)->GetTimestamp(),
1373 controller
.GetEntryAtIndex(0)->GetTimestamp());
1375 test_rvh()->SendNavigate(0, url2
);
1376 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1377 navigation_entry_committed_counter_
= 0;
1379 // The back navigation completed successfully.
1380 EXPECT_EQ(controller
.GetEntryCount(), 2);
1381 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1382 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1383 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1384 EXPECT_FALSE(controller
.GetPendingEntry());
1385 EXPECT_FALSE(controller
.CanGoBack());
1386 EXPECT_FALSE(controller
.CanGoToOffset(-1));
1387 EXPECT_TRUE(controller
.CanGoForward());
1388 EXPECT_TRUE(controller
.CanGoToOffset(1));
1389 EXPECT_FALSE(controller
.CanGoToOffset(2)); // Cannot go foward 2 steps.
1391 // Timestamp for entry 0 should be on or after that of entry 1
1392 // (since we went back to it).
1393 EXPECT_GE(controller
.GetEntryAtIndex(0)->GetTimestamp(),
1394 controller
.GetEntryAtIndex(1)->GetTimestamp());
1397 // Tests what happens when a back navigation produces a new page.
1398 TEST_F(NavigationControllerTest
, Back_GeneratesNewPage
) {
1399 NavigationControllerImpl
& controller
= controller_impl();
1400 TestNotificationTracker notifications
;
1401 RegisterForAllNavNotifications(¬ifications
, &controller
);
1403 const GURL
url1("http://foo/1");
1404 const GURL
url2("http://foo/2");
1405 const GURL
url3("http://foo/3");
1408 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1409 test_rvh()->SendNavigate(0, url1
);
1410 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1411 navigation_entry_committed_counter_
= 0;
1413 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1414 test_rvh()->SendNavigate(1, url2
);
1415 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1416 navigation_entry_committed_counter_
= 0;
1418 controller
.GoBack();
1419 EXPECT_EQ(0U, notifications
.size());
1421 // We should now have a pending navigation to go back.
1422 EXPECT_EQ(controller
.GetEntryCount(), 2);
1423 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1424 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1425 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1426 EXPECT_TRUE(controller
.GetPendingEntry());
1427 EXPECT_FALSE(controller
.CanGoBack());
1428 EXPECT_TRUE(controller
.CanGoForward());
1430 test_rvh()->SendNavigate(2, url3
);
1431 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1432 navigation_entry_committed_counter_
= 0;
1434 // The back navigation resulted in a completely new navigation.
1435 // TODO(darin): perhaps this behavior will be confusing to users?
1436 EXPECT_EQ(controller
.GetEntryCount(), 3);
1437 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 2);
1438 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1439 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1440 EXPECT_FALSE(controller
.GetPendingEntry());
1441 EXPECT_TRUE(controller
.CanGoBack());
1442 EXPECT_FALSE(controller
.CanGoForward());
1445 // Receives a back message when there is a new pending navigation entry.
1446 TEST_F(NavigationControllerTest
, Back_NewPending
) {
1447 NavigationControllerImpl
& controller
= controller_impl();
1448 TestNotificationTracker notifications
;
1449 RegisterForAllNavNotifications(¬ifications
, &controller
);
1451 const GURL
kUrl1("http://foo1");
1452 const GURL
kUrl2("http://foo2");
1453 const GURL
kUrl3("http://foo3");
1455 // First navigate two places so we have some back history.
1456 test_rvh()->SendNavigate(0, kUrl1
);
1457 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1458 navigation_entry_committed_counter_
= 0;
1460 // controller.LoadURL(kUrl2, PAGE_TRANSITION_TYPED);
1461 test_rvh()->SendNavigate(1, kUrl2
);
1462 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1463 navigation_entry_committed_counter_
= 0;
1465 // Now start a new pending navigation and go back before it commits.
1466 controller
.LoadURL(kUrl3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1467 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1468 EXPECT_EQ(kUrl3
, controller
.GetPendingEntry()->GetURL());
1469 controller
.GoBack();
1471 // The pending navigation should now be the "back" item and the new one
1473 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
1474 EXPECT_EQ(kUrl1
, controller
.GetPendingEntry()->GetURL());
1477 // Receives a back message when there is a different renavigation already
1479 TEST_F(NavigationControllerTest
, Back_OtherBackPending
) {
1480 NavigationControllerImpl
& controller
= controller_impl();
1481 const GURL
kUrl1("http://foo/1");
1482 const GURL
kUrl2("http://foo/2");
1483 const GURL
kUrl3("http://foo/3");
1485 // First navigate three places so we have some back history.
1486 test_rvh()->SendNavigate(0, kUrl1
);
1487 test_rvh()->SendNavigate(1, kUrl2
);
1488 test_rvh()->SendNavigate(2, kUrl3
);
1490 // With nothing pending, say we get a navigation to the second entry.
1491 test_rvh()->SendNavigate(1, kUrl2
);
1493 // We know all the entries have the same site instance, so we can just grab
1494 // a random one for looking up other entries.
1495 SiteInstance
* site_instance
=
1496 NavigationEntryImpl::FromNavigationEntry(
1497 controller
.GetLastCommittedEntry())->site_instance();
1499 // That second URL should be the last committed and it should have gotten the
1501 EXPECT_EQ(kUrl2
, controller
.GetEntryWithPageID(site_instance
, 1)->GetURL());
1502 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1503 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1505 // Now go forward to the last item again and say it was committed.
1506 controller
.GoForward();
1507 test_rvh()->SendNavigate(2, kUrl3
);
1509 // Now start going back one to the second page. It will be pending.
1510 controller
.GoBack();
1511 EXPECT_EQ(1, controller
.GetPendingEntryIndex());
1512 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1514 // Not synthesize a totally new back event to the first page. This will not
1515 // match the pending one.
1516 test_rvh()->SendNavigate(0, kUrl1
);
1518 // The committed navigation should clear the pending entry.
1519 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1521 // But the navigated entry should be the last committed.
1522 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1523 EXPECT_EQ(kUrl1
, controller
.GetLastCommittedEntry()->GetURL());
1526 // Tests what happens when we navigate forward successfully.
1527 TEST_F(NavigationControllerTest
, Forward
) {
1528 NavigationControllerImpl
& controller
= controller_impl();
1529 TestNotificationTracker notifications
;
1530 RegisterForAllNavNotifications(¬ifications
, &controller
);
1532 const GURL
url1("http://foo1");
1533 const GURL
url2("http://foo2");
1535 test_rvh()->SendNavigate(0, url1
);
1536 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1537 navigation_entry_committed_counter_
= 0;
1539 test_rvh()->SendNavigate(1, url2
);
1540 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1541 navigation_entry_committed_counter_
= 0;
1543 controller
.GoBack();
1544 test_rvh()->SendNavigate(0, url1
);
1545 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1546 navigation_entry_committed_counter_
= 0;
1548 controller
.GoForward();
1550 // We should now have a pending navigation to go forward.
1551 EXPECT_EQ(controller
.GetEntryCount(), 2);
1552 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1553 EXPECT_EQ(controller
.GetPendingEntryIndex(), 1);
1554 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1555 EXPECT_TRUE(controller
.GetPendingEntry());
1556 EXPECT_TRUE(controller
.CanGoBack());
1557 EXPECT_TRUE(controller
.CanGoToOffset(-1));
1558 EXPECT_FALSE(controller
.CanGoToOffset(-2)); // Cannot go back 2 steps.
1559 EXPECT_FALSE(controller
.CanGoForward());
1560 EXPECT_FALSE(controller
.CanGoToOffset(1));
1562 // Timestamp for entry 0 should be on or after that of entry 1
1563 // (since we went back to it).
1564 EXPECT_FALSE(controller
.GetEntryAtIndex(0)->GetTimestamp().is_null());
1565 EXPECT_GE(controller
.GetEntryAtIndex(0)->GetTimestamp(),
1566 controller
.GetEntryAtIndex(1)->GetTimestamp());
1568 test_rvh()->SendNavigate(1, url2
);
1569 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1570 navigation_entry_committed_counter_
= 0;
1572 // The forward navigation completed successfully.
1573 EXPECT_EQ(controller
.GetEntryCount(), 2);
1574 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1575 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1576 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1577 EXPECT_FALSE(controller
.GetPendingEntry());
1578 EXPECT_TRUE(controller
.CanGoBack());
1579 EXPECT_TRUE(controller
.CanGoToOffset(-1));
1580 EXPECT_FALSE(controller
.CanGoToOffset(-2)); // Cannot go back 2 steps.
1581 EXPECT_FALSE(controller
.CanGoForward());
1582 EXPECT_FALSE(controller
.CanGoToOffset(1));
1584 // Timestamp for entry 1 should be on or after that of entry 0
1585 // (since we went forward to it).
1586 EXPECT_GE(controller
.GetEntryAtIndex(1)->GetTimestamp(),
1587 controller
.GetEntryAtIndex(0)->GetTimestamp());
1590 // Tests what happens when a forward navigation produces a new page.
1591 TEST_F(NavigationControllerTest
, Forward_GeneratesNewPage
) {
1592 NavigationControllerImpl
& controller
= controller_impl();
1593 TestNotificationTracker notifications
;
1594 RegisterForAllNavNotifications(¬ifications
, &controller
);
1596 const GURL
url1("http://foo1");
1597 const GURL
url2("http://foo2");
1598 const GURL
url3("http://foo3");
1600 test_rvh()->SendNavigate(0, url1
);
1601 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1602 navigation_entry_committed_counter_
= 0;
1603 test_rvh()->SendNavigate(1, url2
);
1604 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1605 navigation_entry_committed_counter_
= 0;
1607 controller
.GoBack();
1608 test_rvh()->SendNavigate(0, url1
);
1609 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1610 navigation_entry_committed_counter_
= 0;
1612 controller
.GoForward();
1613 EXPECT_EQ(0U, notifications
.size());
1615 // Should now have a pending navigation to go forward.
1616 EXPECT_EQ(controller
.GetEntryCount(), 2);
1617 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1618 EXPECT_EQ(controller
.GetPendingEntryIndex(), 1);
1619 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1620 EXPECT_TRUE(controller
.GetPendingEntry());
1621 EXPECT_TRUE(controller
.CanGoBack());
1622 EXPECT_FALSE(controller
.CanGoForward());
1624 test_rvh()->SendNavigate(2, url3
);
1625 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1626 navigation_entry_committed_counter_
= 0;
1627 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_LIST_PRUNED
));
1629 EXPECT_EQ(controller
.GetEntryCount(), 2);
1630 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1631 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1632 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1633 EXPECT_FALSE(controller
.GetPendingEntry());
1634 EXPECT_TRUE(controller
.CanGoBack());
1635 EXPECT_FALSE(controller
.CanGoForward());
1638 // Two consequent navigation for the same URL entered in should be considered
1639 // as SAME_PAGE navigation even when we are redirected to some other page.
1640 TEST_F(NavigationControllerTest
, Redirect
) {
1641 NavigationControllerImpl
& controller
= controller_impl();
1642 TestNotificationTracker notifications
;
1643 RegisterForAllNavNotifications(¬ifications
, &controller
);
1645 const GURL
url1("http://foo1");
1646 const GURL
url2("http://foo2"); // Redirection target
1649 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1651 EXPECT_EQ(0U, notifications
.size());
1652 test_rvh()->SendNavigate(0, url2
);
1653 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1654 navigation_entry_committed_counter_
= 0;
1657 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1659 EXPECT_TRUE(controller
.GetPendingEntry());
1660 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1661 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
1663 ViewHostMsg_FrameNavigate_Params params
;
1666 params
.transition
= PAGE_TRANSITION_SERVER_REDIRECT
;
1667 params
.redirects
.push_back(GURL("http://foo1"));
1668 params
.redirects
.push_back(GURL("http://foo2"));
1669 params
.should_update_history
= false;
1670 params
.gesture
= NavigationGestureAuto
;
1671 params
.is_post
= false;
1672 params
.page_state
= PageState::CreateFromURL(url2
);
1674 LoadCommittedDetails details
;
1676 EXPECT_EQ(0U, notifications
.size());
1677 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
1678 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1679 navigation_entry_committed_counter_
= 0;
1681 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_SAME_PAGE
);
1682 EXPECT_EQ(controller
.GetEntryCount(), 1);
1683 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1684 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1685 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1686 EXPECT_FALSE(controller
.GetPendingEntry());
1687 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
1689 EXPECT_FALSE(controller
.CanGoBack());
1690 EXPECT_FALSE(controller
.CanGoForward());
1693 // Similar to Redirect above, but the first URL is requested by POST,
1694 // the second URL is requested by GET. NavigationEntry::has_post_data_
1695 // must be cleared. http://crbug.com/21245
1696 TEST_F(NavigationControllerTest
, PostThenRedirect
) {
1697 NavigationControllerImpl
& controller
= controller_impl();
1698 TestNotificationTracker notifications
;
1699 RegisterForAllNavNotifications(¬ifications
, &controller
);
1701 const GURL
url1("http://foo1");
1702 const GURL
url2("http://foo2"); // Redirection target
1704 // First request as POST
1705 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1706 controller
.GetVisibleEntry()->SetHasPostData(true);
1708 EXPECT_EQ(0U, notifications
.size());
1709 test_rvh()->SendNavigate(0, url2
);
1710 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1711 navigation_entry_committed_counter_
= 0;
1714 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1716 EXPECT_TRUE(controller
.GetPendingEntry());
1717 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1718 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
1720 ViewHostMsg_FrameNavigate_Params params
;
1723 params
.transition
= PAGE_TRANSITION_SERVER_REDIRECT
;
1724 params
.redirects
.push_back(GURL("http://foo1"));
1725 params
.redirects
.push_back(GURL("http://foo2"));
1726 params
.should_update_history
= false;
1727 params
.gesture
= NavigationGestureAuto
;
1728 params
.is_post
= false;
1729 params
.page_state
= PageState::CreateFromURL(url2
);
1731 LoadCommittedDetails details
;
1733 EXPECT_EQ(0U, notifications
.size());
1734 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
1735 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1736 navigation_entry_committed_counter_
= 0;
1738 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_SAME_PAGE
);
1739 EXPECT_EQ(controller
.GetEntryCount(), 1);
1740 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1741 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1742 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1743 EXPECT_FALSE(controller
.GetPendingEntry());
1744 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
1745 EXPECT_FALSE(controller
.GetVisibleEntry()->GetHasPostData());
1747 EXPECT_FALSE(controller
.CanGoBack());
1748 EXPECT_FALSE(controller
.CanGoForward());
1751 // A redirect right off the bat should be a NEW_PAGE.
1752 TEST_F(NavigationControllerTest
, ImmediateRedirect
) {
1753 NavigationControllerImpl
& controller
= controller_impl();
1754 TestNotificationTracker notifications
;
1755 RegisterForAllNavNotifications(¬ifications
, &controller
);
1757 const GURL
url1("http://foo1");
1758 const GURL
url2("http://foo2"); // Redirection target
1761 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1763 EXPECT_TRUE(controller
.GetPendingEntry());
1764 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1765 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
1767 ViewHostMsg_FrameNavigate_Params params
;
1770 params
.transition
= PAGE_TRANSITION_SERVER_REDIRECT
;
1771 params
.redirects
.push_back(GURL("http://foo1"));
1772 params
.redirects
.push_back(GURL("http://foo2"));
1773 params
.should_update_history
= false;
1774 params
.gesture
= NavigationGestureAuto
;
1775 params
.is_post
= false;
1776 params
.page_state
= PageState::CreateFromURL(url2
);
1778 LoadCommittedDetails details
;
1780 EXPECT_EQ(0U, notifications
.size());
1781 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
1782 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1783 navigation_entry_committed_counter_
= 0;
1785 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_NEW_PAGE
);
1786 EXPECT_EQ(controller
.GetEntryCount(), 1);
1787 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1788 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1789 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1790 EXPECT_FALSE(controller
.GetPendingEntry());
1791 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
1793 EXPECT_FALSE(controller
.CanGoBack());
1794 EXPECT_FALSE(controller
.CanGoForward());
1797 // Tests navigation via link click within a subframe. A new navigation entry
1798 // should be created.
1799 TEST_F(NavigationControllerTest
, NewSubframe
) {
1800 NavigationControllerImpl
& controller
= controller_impl();
1801 TestNotificationTracker notifications
;
1802 RegisterForAllNavNotifications(¬ifications
, &controller
);
1804 const GURL
url1("http://foo1");
1805 test_rvh()->SendNavigate(0, url1
);
1806 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1807 navigation_entry_committed_counter_
= 0;
1809 const GURL
url2("http://foo2");
1810 ViewHostMsg_FrameNavigate_Params params
;
1813 params
.transition
= PAGE_TRANSITION_MANUAL_SUBFRAME
;
1814 params
.should_update_history
= false;
1815 params
.gesture
= NavigationGestureUser
;
1816 params
.is_post
= false;
1817 params
.page_state
= PageState::CreateFromURL(url2
);
1819 LoadCommittedDetails details
;
1820 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
1821 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1822 navigation_entry_committed_counter_
= 0;
1823 EXPECT_EQ(url1
, details
.previous_url
);
1824 EXPECT_FALSE(details
.is_in_page
);
1825 EXPECT_FALSE(details
.is_main_frame
);
1827 // The new entry should be appended.
1828 EXPECT_EQ(2, controller
.GetEntryCount());
1830 // New entry should refer to the new page, but the old URL (entries only
1831 // reflect the toplevel URL).
1832 EXPECT_EQ(url1
, details
.entry
->GetURL());
1833 EXPECT_EQ(params
.page_id
, details
.entry
->GetPageID());
1836 // Some pages create a popup, then write an iframe into it. This causes a
1837 // subframe navigation without having any committed entry. Such navigations
1838 // just get thrown on the ground, but we shouldn't crash.
1839 TEST_F(NavigationControllerTest
, SubframeOnEmptyPage
) {
1840 NavigationControllerImpl
& controller
= controller_impl();
1841 TestNotificationTracker notifications
;
1842 RegisterForAllNavNotifications(¬ifications
, &controller
);
1844 // Navigation controller currently has no entries.
1845 const GURL
url("http://foo2");
1846 ViewHostMsg_FrameNavigate_Params params
;
1849 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
1850 params
.should_update_history
= false;
1851 params
.gesture
= NavigationGestureAuto
;
1852 params
.is_post
= false;
1853 params
.page_state
= PageState::CreateFromURL(url
);
1855 LoadCommittedDetails details
;
1856 EXPECT_FALSE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
1857 EXPECT_EQ(0U, notifications
.size());
1860 // Auto subframes are ones the page loads automatically like ads. They should
1861 // not create new navigation entries.
1862 TEST_F(NavigationControllerTest
, AutoSubframe
) {
1863 NavigationControllerImpl
& controller
= controller_impl();
1864 TestNotificationTracker notifications
;
1865 RegisterForAllNavNotifications(¬ifications
, &controller
);
1867 const GURL
url1("http://foo1");
1868 test_rvh()->SendNavigate(0, url1
);
1869 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1870 navigation_entry_committed_counter_
= 0;
1872 const GURL
url2("http://foo2");
1873 ViewHostMsg_FrameNavigate_Params params
;
1876 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
1877 params
.should_update_history
= false;
1878 params
.gesture
= NavigationGestureUser
;
1879 params
.is_post
= false;
1880 params
.page_state
= PageState::CreateFromURL(url2
);
1882 // Navigating should do nothing.
1883 LoadCommittedDetails details
;
1884 EXPECT_FALSE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
1885 EXPECT_EQ(0U, notifications
.size());
1887 // There should still be only one entry.
1888 EXPECT_EQ(1, controller
.GetEntryCount());
1891 // Tests navigation and then going back to a subframe navigation.
1892 TEST_F(NavigationControllerTest
, BackSubframe
) {
1893 NavigationControllerImpl
& controller
= controller_impl();
1894 TestNotificationTracker notifications
;
1895 RegisterForAllNavNotifications(¬ifications
, &controller
);
1898 const GURL
url1("http://foo1");
1899 test_rvh()->SendNavigate(0, url1
);
1900 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1901 navigation_entry_committed_counter_
= 0;
1903 // First manual subframe navigation.
1904 const GURL
url2("http://foo2");
1905 ViewHostMsg_FrameNavigate_Params params
;
1908 params
.transition
= PAGE_TRANSITION_MANUAL_SUBFRAME
;
1909 params
.should_update_history
= false;
1910 params
.gesture
= NavigationGestureUser
;
1911 params
.is_post
= false;
1912 params
.page_state
= PageState::CreateFromURL(url2
);
1914 // This should generate a new entry.
1915 LoadCommittedDetails details
;
1916 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
1917 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1918 navigation_entry_committed_counter_
= 0;
1919 EXPECT_EQ(2, controller
.GetEntryCount());
1921 // Second manual subframe navigation should also make a new entry.
1922 const GURL
url3("http://foo3");
1925 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
1926 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1927 navigation_entry_committed_counter_
= 0;
1928 EXPECT_EQ(3, controller
.GetEntryCount());
1929 EXPECT_EQ(2, controller
.GetCurrentEntryIndex());
1932 controller
.GoBack();
1935 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
1936 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1937 navigation_entry_committed_counter_
= 0;
1938 EXPECT_EQ(3, controller
.GetEntryCount());
1939 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
1940 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1941 EXPECT_FALSE(controller
.GetPendingEntry());
1943 // Go back one more.
1944 controller
.GoBack();
1947 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
1948 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1949 navigation_entry_committed_counter_
= 0;
1950 EXPECT_EQ(3, controller
.GetEntryCount());
1951 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
1952 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1953 EXPECT_FALSE(controller
.GetPendingEntry());
1956 TEST_F(NavigationControllerTest
, LinkClick
) {
1957 NavigationControllerImpl
& controller
= controller_impl();
1958 TestNotificationTracker notifications
;
1959 RegisterForAllNavNotifications(¬ifications
, &controller
);
1961 const GURL
url1("http://foo1");
1962 const GURL
url2("http://foo2");
1964 test_rvh()->SendNavigate(0, url1
);
1965 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1966 navigation_entry_committed_counter_
= 0;
1968 test_rvh()->SendNavigate(1, url2
);
1969 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1970 navigation_entry_committed_counter_
= 0;
1972 // Should not have produced a new session history entry.
1973 EXPECT_EQ(controller
.GetEntryCount(), 2);
1974 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1975 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1976 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1977 EXPECT_FALSE(controller
.GetPendingEntry());
1978 EXPECT_TRUE(controller
.CanGoBack());
1979 EXPECT_FALSE(controller
.CanGoForward());
1982 TEST_F(NavigationControllerTest
, InPage
) {
1983 NavigationControllerImpl
& controller
= controller_impl();
1984 TestNotificationTracker notifications
;
1985 RegisterForAllNavNotifications(¬ifications
, &controller
);
1988 const GURL
url1("http://foo");
1989 test_rvh()->SendNavigate(0, url1
);
1990 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1991 navigation_entry_committed_counter_
= 0;
1993 // Ensure main page navigation to same url respects the was_within_same_page
1994 // hint provided in the params.
1995 ViewHostMsg_FrameNavigate_Params self_params
;
1996 self_params
.page_id
= 0;
1997 self_params
.url
= url1
;
1998 self_params
.transition
= PAGE_TRANSITION_LINK
;
1999 self_params
.should_update_history
= false;
2000 self_params
.gesture
= NavigationGestureUser
;
2001 self_params
.is_post
= false;
2002 self_params
.page_state
= PageState::CreateFromURL(url1
);
2003 self_params
.was_within_same_page
= true;
2005 LoadCommittedDetails details
;
2006 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), self_params
,
2008 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2009 navigation_entry_committed_counter_
= 0;
2010 EXPECT_TRUE(details
.is_in_page
);
2011 EXPECT_TRUE(details
.did_replace_entry
);
2012 EXPECT_EQ(1, controller
.GetEntryCount());
2014 // Fragment navigation to a new page_id.
2015 const GURL
url2("http://foo#a");
2016 ViewHostMsg_FrameNavigate_Params params
;
2019 params
.transition
= PAGE_TRANSITION_LINK
;
2020 params
.should_update_history
= false;
2021 params
.gesture
= NavigationGestureUser
;
2022 params
.is_post
= false;
2023 params
.page_state
= PageState::CreateFromURL(url2
);
2024 params
.was_within_same_page
= true;
2026 // This should generate a new entry.
2027 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
2028 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2029 navigation_entry_committed_counter_
= 0;
2030 EXPECT_TRUE(details
.is_in_page
);
2031 EXPECT_FALSE(details
.did_replace_entry
);
2032 EXPECT_EQ(2, controller
.GetEntryCount());
2035 ViewHostMsg_FrameNavigate_Params
back_params(params
);
2036 controller
.GoBack();
2037 back_params
.url
= url1
;
2038 back_params
.page_id
= 0;
2039 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), back_params
,
2041 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2042 navigation_entry_committed_counter_
= 0;
2043 EXPECT_TRUE(details
.is_in_page
);
2044 EXPECT_EQ(2, controller
.GetEntryCount());
2045 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
2046 EXPECT_EQ(back_params
.url
, controller
.GetVisibleEntry()->GetURL());
2049 ViewHostMsg_FrameNavigate_Params
forward_params(params
);
2050 controller
.GoForward();
2051 forward_params
.url
= url2
;
2052 forward_params
.page_id
= 1;
2053 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), forward_params
,
2055 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2056 navigation_entry_committed_counter_
= 0;
2057 EXPECT_TRUE(details
.is_in_page
);
2058 EXPECT_EQ(2, controller
.GetEntryCount());
2059 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
2060 EXPECT_EQ(forward_params
.url
,
2061 controller
.GetVisibleEntry()->GetURL());
2063 // Now go back and forward again. This is to work around a bug where we would
2064 // compare the incoming URL with the last committed entry rather than the
2065 // one identified by an existing page ID. This would result in the second URL
2066 // losing the reference fragment when you navigate away from it and then back.
2067 controller
.GoBack();
2068 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), back_params
,
2070 controller
.GoForward();
2071 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), forward_params
,
2073 EXPECT_EQ(forward_params
.url
,
2074 controller
.GetVisibleEntry()->GetURL());
2076 // Finally, navigate to an unrelated URL to make sure in_page is not sticky.
2077 const GURL
url3("http://bar");
2080 navigation_entry_committed_counter_
= 0;
2081 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
2082 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2083 navigation_entry_committed_counter_
= 0;
2084 EXPECT_FALSE(details
.is_in_page
);
2085 EXPECT_EQ(3, controller
.GetEntryCount());
2086 EXPECT_EQ(2, controller
.GetCurrentEntryIndex());
2089 TEST_F(NavigationControllerTest
, InPage_Replace
) {
2090 NavigationControllerImpl
& controller
= controller_impl();
2091 TestNotificationTracker notifications
;
2092 RegisterForAllNavNotifications(¬ifications
, &controller
);
2095 const GURL
url1("http://foo");
2096 test_rvh()->SendNavigate(0, url1
);
2097 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2098 navigation_entry_committed_counter_
= 0;
2100 // First navigation.
2101 const GURL
url2("http://foo#a");
2102 ViewHostMsg_FrameNavigate_Params params
;
2103 params
.page_id
= 0; // Same page_id
2105 params
.transition
= PAGE_TRANSITION_LINK
;
2106 params
.should_update_history
= false;
2107 params
.gesture
= NavigationGestureUser
;
2108 params
.is_post
= false;
2109 params
.page_state
= PageState::CreateFromURL(url2
);
2111 // This should NOT generate a new entry, nor prune the list.
2112 LoadCommittedDetails details
;
2113 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
2114 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2115 navigation_entry_committed_counter_
= 0;
2116 EXPECT_TRUE(details
.is_in_page
);
2117 EXPECT_TRUE(details
.did_replace_entry
);
2118 EXPECT_EQ(1, controller
.GetEntryCount());
2121 // Tests for http://crbug.com/40395
2124 // window.location.replace("#a");
2125 // window.location='http://foo3/';
2127 TEST_F(NavigationControllerTest
, ClientRedirectAfterInPageNavigation
) {
2128 NavigationControllerImpl
& controller
= controller_impl();
2129 TestNotificationTracker notifications
;
2130 RegisterForAllNavNotifications(¬ifications
, &controller
);
2132 // Load an initial page.
2134 const GURL
url("http://foo/");
2135 test_rvh()->SendNavigate(0, url
);
2136 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2137 navigation_entry_committed_counter_
= 0;
2140 // Navigate to a new page.
2142 const GURL
url("http://foo2/");
2143 test_rvh()->SendNavigate(1, url
);
2144 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2145 navigation_entry_committed_counter_
= 0;
2148 // Navigate within the page.
2150 const GURL
url("http://foo2/#a");
2151 ViewHostMsg_FrameNavigate_Params params
;
2152 params
.page_id
= 1; // Same page_id
2154 params
.transition
= PAGE_TRANSITION_LINK
;
2155 params
.redirects
.push_back(url
);
2156 params
.should_update_history
= true;
2157 params
.gesture
= NavigationGestureUnknown
;
2158 params
.is_post
= false;
2159 params
.page_state
= PageState::CreateFromURL(url
);
2161 // This should NOT generate a new entry, nor prune the list.
2162 LoadCommittedDetails details
;
2163 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
2164 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2165 navigation_entry_committed_counter_
= 0;
2166 EXPECT_TRUE(details
.is_in_page
);
2167 EXPECT_TRUE(details
.did_replace_entry
);
2168 EXPECT_EQ(2, controller
.GetEntryCount());
2171 // Perform a client redirect to a new page.
2173 const GURL
url("http://foo3/");
2174 ViewHostMsg_FrameNavigate_Params params
;
2175 params
.page_id
= 2; // New page_id
2177 params
.transition
= PAGE_TRANSITION_CLIENT_REDIRECT
;
2178 params
.redirects
.push_back(GURL("http://foo2/#a"));
2179 params
.redirects
.push_back(url
);
2180 params
.should_update_history
= true;
2181 params
.gesture
= NavigationGestureUnknown
;
2182 params
.is_post
= false;
2183 params
.page_state
= PageState::CreateFromURL(url
);
2185 // This SHOULD generate a new entry.
2186 LoadCommittedDetails details
;
2187 EXPECT_TRUE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
2188 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2189 navigation_entry_committed_counter_
= 0;
2190 EXPECT_FALSE(details
.is_in_page
);
2191 EXPECT_EQ(3, controller
.GetEntryCount());
2194 // Verify that BACK brings us back to http://foo2/.
2196 const GURL
url("http://foo2/");
2197 controller
.GoBack();
2198 test_rvh()->SendNavigate(1, url
);
2199 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2200 navigation_entry_committed_counter_
= 0;
2201 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
2205 // NotificationObserver implementation used in verifying we've received the
2206 // NOTIFICATION_NAV_LIST_PRUNED method.
2207 class PrunedListener
: public NotificationObserver
{
2209 explicit PrunedListener(NavigationControllerImpl
* controller
)
2210 : notification_count_(0) {
2211 registrar_
.Add(this, NOTIFICATION_NAV_LIST_PRUNED
,
2212 Source
<NavigationController
>(controller
));
2215 virtual void Observe(int type
,
2216 const NotificationSource
& source
,
2217 const NotificationDetails
& details
) OVERRIDE
{
2218 if (type
== NOTIFICATION_NAV_LIST_PRUNED
) {
2219 notification_count_
++;
2220 details_
= *(Details
<PrunedDetails
>(details
).ptr());
2224 // Number of times NAV_LIST_PRUNED has been observed.
2225 int notification_count_
;
2227 // Details from the last NAV_LIST_PRUNED.
2228 PrunedDetails details_
;
2231 NotificationRegistrar registrar_
;
2233 DISALLOW_COPY_AND_ASSIGN(PrunedListener
);
2236 // Tests that we limit the number of navigation entries created correctly.
2237 TEST_F(NavigationControllerTest
, EnforceMaxNavigationCount
) {
2238 NavigationControllerImpl
& controller
= controller_impl();
2239 size_t original_count
= NavigationControllerImpl::max_entry_count();
2240 const int kMaxEntryCount
= 5;
2242 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
2245 // Load up to the max count, all entries should be there.
2246 for (url_index
= 0; url_index
< kMaxEntryCount
; url_index
++) {
2247 GURL
url(base::StringPrintf("http://www.a.com/%d", url_index
));
2249 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2250 test_rvh()->SendNavigate(url_index
, url
);
2253 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
2255 // Created a PrunedListener to observe prune notifications.
2256 PrunedListener
listener(&controller
);
2258 // Navigate some more.
2259 GURL
url(base::StringPrintf("http://www.a.com/%d", url_index
));
2261 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2262 test_rvh()->SendNavigate(url_index
, url
);
2265 // We should have got a pruned navigation.
2266 EXPECT_EQ(1, listener
.notification_count_
);
2267 EXPECT_TRUE(listener
.details_
.from_front
);
2268 EXPECT_EQ(1, listener
.details_
.count
);
2270 // We expect http://www.a.com/0 to be gone.
2271 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
2272 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(),
2273 GURL("http:////www.a.com/1"));
2275 // More navigations.
2276 for (int i
= 0; i
< 3; i
++) {
2277 url
= GURL(base::StringPrintf("http:////www.a.com/%d", url_index
));
2279 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2280 test_rvh()->SendNavigate(url_index
, url
);
2283 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
2284 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(),
2285 GURL("http:////www.a.com/4"));
2287 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
2290 // Tests that we can do a restore and navigate to the restored entries and
2291 // everything is updated properly. This can be tricky since there is no
2292 // SiteInstance for the entries created initially.
2293 TEST_F(NavigationControllerTest
, RestoreNavigate
) {
2294 // Create a NavigationController with a restored set of tabs.
2295 GURL
url("http://foo");
2296 std::vector
<NavigationEntry
*> entries
;
2297 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
2298 url
, Referrer(), PAGE_TRANSITION_RELOAD
, false, std::string(),
2300 entry
->SetPageID(0);
2301 entry
->SetTitle(base::ASCIIToUTF16("Title"));
2302 entry
->SetPageState(PageState::CreateFromEncodedData("state"));
2303 const base::Time timestamp
= base::Time::Now();
2304 entry
->SetTimestamp(timestamp
);
2305 entries
.push_back(entry
);
2306 scoped_ptr
<WebContentsImpl
> our_contents(static_cast<WebContentsImpl
*>(
2307 WebContents::Create(WebContents::CreateParams(browser_context()))));
2308 NavigationControllerImpl
& our_controller
= our_contents
->GetController();
2309 our_controller
.Restore(
2311 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2313 ASSERT_EQ(0u, entries
.size());
2315 // Before navigating to the restored entry, it should have a restore_type
2316 // and no SiteInstance.
2317 ASSERT_EQ(1, our_controller
.GetEntryCount());
2318 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2319 NavigationEntryImpl::FromNavigationEntry(
2320 our_controller
.GetEntryAtIndex(0))->restore_type());
2321 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
2322 our_controller
.GetEntryAtIndex(0))->site_instance());
2324 // After navigating, we should have one entry, and it should be "pending".
2325 // It should now have a SiteInstance and no restore_type.
2326 our_controller
.GoToIndex(0);
2327 EXPECT_EQ(1, our_controller
.GetEntryCount());
2328 EXPECT_EQ(our_controller
.GetEntryAtIndex(0),
2329 our_controller
.GetPendingEntry());
2330 EXPECT_EQ(0, our_controller
.GetEntryAtIndex(0)->GetPageID());
2331 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2332 NavigationEntryImpl::FromNavigationEntry
2333 (our_controller
.GetEntryAtIndex(0))->restore_type());
2334 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
2335 our_controller
.GetEntryAtIndex(0))->site_instance());
2337 // Timestamp should remain the same before the navigation finishes.
2338 EXPECT_EQ(timestamp
, our_controller
.GetEntryAtIndex(0)->GetTimestamp());
2340 // Say we navigated to that entry.
2341 ViewHostMsg_FrameNavigate_Params params
;
2344 params
.transition
= PAGE_TRANSITION_LINK
;
2345 params
.should_update_history
= false;
2346 params
.gesture
= NavigationGestureUser
;
2347 params
.is_post
= false;
2348 params
.page_state
= PageState::CreateFromURL(url
);
2349 LoadCommittedDetails details
;
2350 our_controller
.RendererDidNavigate(our_contents
->GetRenderViewHost(), params
,
2353 // There should be no longer any pending entry and one committed one. This
2354 // means that we were able to locate the entry, assign its site instance, and
2355 // commit it properly.
2356 EXPECT_EQ(1, our_controller
.GetEntryCount());
2357 EXPECT_EQ(0, our_controller
.GetLastCommittedEntryIndex());
2358 EXPECT_FALSE(our_controller
.GetPendingEntry());
2360 NavigationEntryImpl::FromNavigationEntry(
2361 our_controller
.GetLastCommittedEntry())->site_instance()->
2363 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2364 NavigationEntryImpl::FromNavigationEntry(
2365 our_controller
.GetEntryAtIndex(0))->restore_type());
2367 // Timestamp should have been updated.
2368 EXPECT_GE(our_controller
.GetEntryAtIndex(0)->GetTimestamp(), timestamp
);
2371 // Tests that we can still navigate to a restored entry after a different
2372 // navigation fails and clears the pending entry. http://crbug.com/90085
2373 TEST_F(NavigationControllerTest
, RestoreNavigateAfterFailure
) {
2374 // Create a NavigationController with a restored set of tabs.
2375 GURL
url("http://foo");
2376 std::vector
<NavigationEntry
*> entries
;
2377 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
2378 url
, Referrer(), PAGE_TRANSITION_RELOAD
, false, std::string(),
2380 entry
->SetPageID(0);
2381 entry
->SetTitle(base::ASCIIToUTF16("Title"));
2382 entry
->SetPageState(PageState::CreateFromEncodedData("state"));
2383 entries
.push_back(entry
);
2384 scoped_ptr
<WebContentsImpl
> our_contents(static_cast<WebContentsImpl
*>(
2385 WebContents::Create(WebContents::CreateParams(browser_context()))));
2386 NavigationControllerImpl
& our_controller
= our_contents
->GetController();
2387 our_controller
.Restore(
2388 0, NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
, &entries
);
2389 ASSERT_EQ(0u, entries
.size());
2391 // Before navigating to the restored entry, it should have a restore_type
2392 // and no SiteInstance.
2393 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2394 NavigationEntryImpl::FromNavigationEntry(
2395 our_controller
.GetEntryAtIndex(0))->restore_type());
2396 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
2397 our_controller
.GetEntryAtIndex(0))->site_instance());
2399 // After navigating, we should have one entry, and it should be "pending".
2400 // It should now have a SiteInstance and no restore_type.
2401 our_controller
.GoToIndex(0);
2402 EXPECT_EQ(1, our_controller
.GetEntryCount());
2403 EXPECT_EQ(our_controller
.GetEntryAtIndex(0),
2404 our_controller
.GetPendingEntry());
2405 EXPECT_EQ(0, our_controller
.GetEntryAtIndex(0)->GetPageID());
2406 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2407 NavigationEntryImpl::FromNavigationEntry(
2408 our_controller
.GetEntryAtIndex(0))->restore_type());
2409 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
2410 our_controller
.GetEntryAtIndex(0))->site_instance());
2412 // This pending navigation may have caused a different navigation to fail,
2413 // which causes the pending entry to be cleared.
2414 TestRenderViewHost
* rvh
=
2415 static_cast<TestRenderViewHost
*>(our_contents
->GetRenderViewHost());
2416 FrameHostMsg_DidFailProvisionalLoadWithError_Params fail_load_params
;
2417 fail_load_params
.frame_id
= 1;
2418 fail_load_params
.is_main_frame
= true;
2419 fail_load_params
.error_code
= net::ERR_ABORTED
;
2420 fail_load_params
.error_description
= base::string16();
2421 fail_load_params
.url
= url
;
2422 fail_load_params
.showing_repost_interstitial
= false;
2423 main_test_rfh()->OnMessageReceived(
2424 FrameHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
2427 // Now the pending restored entry commits.
2428 ViewHostMsg_FrameNavigate_Params params
;
2431 params
.transition
= PAGE_TRANSITION_LINK
;
2432 params
.should_update_history
= false;
2433 params
.gesture
= NavigationGestureUser
;
2434 params
.is_post
= false;
2435 params
.page_state
= PageState::CreateFromURL(url
);
2436 LoadCommittedDetails details
;
2437 our_controller
.RendererDidNavigate(rvh
, params
, &details
);
2439 // There should be no pending entry and one committed one.
2440 EXPECT_EQ(1, our_controller
.GetEntryCount());
2441 EXPECT_EQ(0, our_controller
.GetLastCommittedEntryIndex());
2442 EXPECT_FALSE(our_controller
.GetPendingEntry());
2444 NavigationEntryImpl::FromNavigationEntry(
2445 our_controller
.GetLastCommittedEntry())->site_instance()->
2447 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2448 NavigationEntryImpl::FromNavigationEntry(
2449 our_controller
.GetEntryAtIndex(0))->restore_type());
2452 // Make sure that the page type and stuff is correct after an interstitial.
2453 TEST_F(NavigationControllerTest
, Interstitial
) {
2454 NavigationControllerImpl
& controller
= controller_impl();
2455 // First navigate somewhere normal.
2456 const GURL
url1("http://foo");
2458 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2459 test_rvh()->SendNavigate(0, url1
);
2461 // Now navigate somewhere with an interstitial.
2462 const GURL
url2("http://bar");
2464 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2465 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2466 set_page_type(PAGE_TYPE_INTERSTITIAL
);
2468 // At this point the interstitial will be displayed and the load will still
2469 // be pending. If the user continues, the load will commit.
2470 test_rvh()->SendNavigate(1, url2
);
2472 // The page should be a normal page again.
2473 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetURL());
2474 EXPECT_EQ(PAGE_TYPE_NORMAL
,
2475 controller
.GetLastCommittedEntry()->GetPageType());
2478 TEST_F(NavigationControllerTest
, RemoveEntry
) {
2479 NavigationControllerImpl
& controller
= controller_impl();
2480 const GURL
url1("http://foo/1");
2481 const GURL
url2("http://foo/2");
2482 const GURL
url3("http://foo/3");
2483 const GURL
url4("http://foo/4");
2484 const GURL
url5("http://foo/5");
2485 const GURL
pending_url("http://foo/pending");
2486 const GURL
default_url("http://foo/default");
2489 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2490 test_rvh()->SendNavigate(0, url1
);
2492 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2493 test_rvh()->SendNavigate(1, url2
);
2495 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2496 test_rvh()->SendNavigate(2, url3
);
2498 url4
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2499 test_rvh()->SendNavigate(3, url4
);
2501 url5
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2502 test_rvh()->SendNavigate(4, url5
);
2504 // Try to remove the last entry. Will fail because it is the current entry.
2505 EXPECT_FALSE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1));
2506 EXPECT_EQ(5, controller
.GetEntryCount());
2507 EXPECT_EQ(4, controller
.GetLastCommittedEntryIndex());
2509 // Go back, but don't commit yet. Check that we can't delete the current
2510 // and pending entries.
2511 controller
.GoBack();
2512 EXPECT_FALSE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1));
2513 EXPECT_FALSE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 2));
2515 // Now commit and delete the last entry.
2516 test_rvh()->SendNavigate(3, url4
);
2517 EXPECT_TRUE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1));
2518 EXPECT_EQ(4, controller
.GetEntryCount());
2519 EXPECT_EQ(3, controller
.GetLastCommittedEntryIndex());
2520 EXPECT_FALSE(controller
.GetPendingEntry());
2522 // Remove an entry which is not the last committed one.
2523 EXPECT_TRUE(controller
.RemoveEntryAtIndex(0));
2524 EXPECT_EQ(3, controller
.GetEntryCount());
2525 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
2526 EXPECT_FALSE(controller
.GetPendingEntry());
2528 // Remove the 2 remaining entries.
2529 controller
.RemoveEntryAtIndex(1);
2530 controller
.RemoveEntryAtIndex(0);
2532 // This should leave us with only the last committed entry.
2533 EXPECT_EQ(1, controller
.GetEntryCount());
2534 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
2537 // Tests the transient entry, making sure it goes away with all navigations.
2538 TEST_F(NavigationControllerTest
, TransientEntry
) {
2539 NavigationControllerImpl
& controller
= controller_impl();
2540 TestNotificationTracker notifications
;
2541 RegisterForAllNavNotifications(¬ifications
, &controller
);
2543 const GURL
url0("http://foo/0");
2544 const GURL
url1("http://foo/1");
2545 const GURL
url2("http://foo/2");
2546 const GURL
url3("http://foo/3");
2547 const GURL
url3_ref("http://foo/3#bar");
2548 const GURL
url4("http://foo/4");
2549 const GURL
transient_url("http://foo/transient");
2552 url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2553 test_rvh()->SendNavigate(0, url0
);
2555 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2556 test_rvh()->SendNavigate(1, url1
);
2558 notifications
.Reset();
2560 // Adding a transient with no pending entry.
2561 NavigationEntryImpl
* transient_entry
= new NavigationEntryImpl
;
2562 transient_entry
->SetURL(transient_url
);
2563 controller
.SetTransientEntry(transient_entry
);
2565 // We should not have received any notifications.
2566 EXPECT_EQ(0U, notifications
.size());
2569 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2570 EXPECT_EQ(controller
.GetEntryCount(), 3);
2571 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
2572 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
2573 EXPECT_TRUE(controller
.GetLastCommittedEntry());
2574 EXPECT_FALSE(controller
.GetPendingEntry());
2575 EXPECT_TRUE(controller
.CanGoBack());
2576 EXPECT_FALSE(controller
.CanGoForward());
2577 EXPECT_EQ(contents()->GetMaxPageID(), 1);
2581 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2582 test_rvh()->SendNavigate(2, url2
);
2584 // We should have navigated, transient entry should be gone.
2585 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2586 EXPECT_EQ(controller
.GetEntryCount(), 3);
2588 // Add a transient again, then navigate with no pending entry this time.
2589 transient_entry
= new NavigationEntryImpl
;
2590 transient_entry
->SetURL(transient_url
);
2591 controller
.SetTransientEntry(transient_entry
);
2592 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2593 test_rvh()->SendNavigate(3, url3
);
2594 // Transient entry should be gone.
2595 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2596 EXPECT_EQ(controller
.GetEntryCount(), 4);
2598 // Initiate a navigation, add a transient then commit navigation.
2600 url4
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2601 transient_entry
= new NavigationEntryImpl
;
2602 transient_entry
->SetURL(transient_url
);
2603 controller
.SetTransientEntry(transient_entry
);
2604 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2605 test_rvh()->SendNavigate(4, url4
);
2606 EXPECT_EQ(url4
, controller
.GetVisibleEntry()->GetURL());
2607 EXPECT_EQ(controller
.GetEntryCount(), 5);
2609 // Add a transient and go back. This should simply remove the transient.
2610 transient_entry
= new NavigationEntryImpl
;
2611 transient_entry
->SetURL(transient_url
);
2612 controller
.SetTransientEntry(transient_entry
);
2613 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2614 EXPECT_TRUE(controller
.CanGoBack());
2615 EXPECT_FALSE(controller
.CanGoForward());
2616 controller
.GoBack();
2617 // Transient entry should be gone.
2618 EXPECT_EQ(url4
, controller
.GetVisibleEntry()->GetURL());
2619 EXPECT_EQ(controller
.GetEntryCount(), 5);
2620 test_rvh()->SendNavigate(3, url3
);
2622 // Add a transient and go to an entry before the current one.
2623 transient_entry
= new NavigationEntryImpl
;
2624 transient_entry
->SetURL(transient_url
);
2625 controller
.SetTransientEntry(transient_entry
);
2626 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2627 controller
.GoToIndex(1);
2628 // The navigation should have been initiated, transient entry should be gone.
2629 EXPECT_FALSE(controller
.GetTransientEntry());
2630 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
2631 // Visible entry does not update for history navigations until commit.
2632 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2633 test_rvh()->SendNavigate(1, url1
);
2634 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2636 // Add a transient and go to an entry after the current one.
2637 transient_entry
= new NavigationEntryImpl
;
2638 transient_entry
->SetURL(transient_url
);
2639 controller
.SetTransientEntry(transient_entry
);
2640 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2641 controller
.GoToIndex(3);
2642 // The navigation should have been initiated, transient entry should be gone.
2643 // Because of the transient entry that is removed, going to index 3 makes us
2644 // land on url2 (which is visible after the commit).
2645 EXPECT_EQ(url2
, controller
.GetPendingEntry()->GetURL());
2646 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2647 test_rvh()->SendNavigate(2, url2
);
2648 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2650 // Add a transient and go forward.
2651 transient_entry
= new NavigationEntryImpl
;
2652 transient_entry
->SetURL(transient_url
);
2653 controller
.SetTransientEntry(transient_entry
);
2654 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2655 EXPECT_TRUE(controller
.CanGoForward());
2656 controller
.GoForward();
2657 // We should have navigated, transient entry should be gone.
2658 EXPECT_FALSE(controller
.GetTransientEntry());
2659 EXPECT_EQ(url3
, controller
.GetPendingEntry()->GetURL());
2660 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2661 test_rvh()->SendNavigate(3, url3
);
2662 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2664 // Add a transient and do an in-page navigation, replacing the current entry.
2665 transient_entry
= new NavigationEntryImpl
;
2666 transient_entry
->SetURL(transient_url
);
2667 controller
.SetTransientEntry(transient_entry
);
2668 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2669 test_rvh()->SendNavigate(3, url3_ref
);
2670 // Transient entry should be gone.
2671 EXPECT_FALSE(controller
.GetTransientEntry());
2672 EXPECT_EQ(url3_ref
, controller
.GetVisibleEntry()->GetURL());
2674 // Ensure the URLs are correct.
2675 EXPECT_EQ(controller
.GetEntryCount(), 5);
2676 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2677 EXPECT_EQ(controller
.GetEntryAtIndex(1)->GetURL(), url1
);
2678 EXPECT_EQ(controller
.GetEntryAtIndex(2)->GetURL(), url2
);
2679 EXPECT_EQ(controller
.GetEntryAtIndex(3)->GetURL(), url3_ref
);
2680 EXPECT_EQ(controller
.GetEntryAtIndex(4)->GetURL(), url4
);
2683 // Test that Reload initiates a new navigation to a transient entry's URL.
2684 TEST_F(NavigationControllerTest
, ReloadTransient
) {
2685 NavigationControllerImpl
& controller
= controller_impl();
2686 const GURL
url0("http://foo/0");
2687 const GURL
url1("http://foo/1");
2688 const GURL
transient_url("http://foo/transient");
2690 // Load |url0|, and start a pending navigation to |url1|.
2692 url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2693 test_rvh()->SendNavigate(0, url0
);
2695 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2697 // A transient entry is added, interrupting the navigation.
2698 NavigationEntryImpl
* transient_entry
= new NavigationEntryImpl
;
2699 transient_entry
->SetURL(transient_url
);
2700 controller
.SetTransientEntry(transient_entry
);
2701 EXPECT_TRUE(controller
.GetTransientEntry());
2702 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2704 // The page is reloaded, which should remove the pending entry for |url1| and
2705 // the transient entry for |transient_url|, and start a navigation to
2707 controller
.Reload(true);
2708 EXPECT_FALSE(controller
.GetTransientEntry());
2709 EXPECT_TRUE(controller
.GetPendingEntry());
2710 EXPECT_EQ(transient_url
, controller
.GetVisibleEntry()->GetURL());
2711 ASSERT_EQ(controller
.GetEntryCount(), 1);
2712 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2714 // Load of |transient_url| completes.
2715 test_rvh()->SendNavigate(1, transient_url
);
2716 ASSERT_EQ(controller
.GetEntryCount(), 2);
2717 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2718 EXPECT_EQ(controller
.GetEntryAtIndex(1)->GetURL(), transient_url
);
2721 // Ensure that renderer initiated pending entries get replaced, so that we
2722 // don't show a stale virtual URL when a navigation commits.
2723 // See http://crbug.com/266922.
2724 TEST_F(NavigationControllerTest
, RendererInitiatedPendingEntries
) {
2725 NavigationControllerImpl
& controller
= controller_impl();
2726 Navigator
* navigator
=
2727 contents()->GetFrameTree()->root()->navigator();
2729 const GURL
url1("nonexistent:12121");
2730 const GURL
url1_fixed("http://nonexistent:12121/");
2731 const GURL
url2("http://foo");
2733 // We create pending entries for renderer-initiated navigations so that we
2734 // can show them in new tabs when it is safe.
2735 navigator
->DidStartProvisionalLoad(main_test_rfh(), 1, -1, true, url1
);
2737 // Simulate what happens if a BrowserURLHandler rewrites the URL, causing
2738 // the virtual URL to differ from the URL.
2739 controller
.GetPendingEntry()->SetURL(url1_fixed
);
2740 controller
.GetPendingEntry()->SetVirtualURL(url1
);
2742 EXPECT_EQ(url1_fixed
, controller
.GetPendingEntry()->GetURL());
2743 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetVirtualURL());
2745 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2746 is_renderer_initiated());
2748 // If the user clicks another link, we should replace the pending entry.
2749 navigator
->DidStartProvisionalLoad(main_test_rfh(), 1, -1, true, url2
);
2750 EXPECT_EQ(url2
, controller
.GetPendingEntry()->GetURL());
2751 EXPECT_EQ(url2
, controller
.GetPendingEntry()->GetVirtualURL());
2753 // Once it commits, the URL and virtual URL should reflect the actual page.
2754 test_rvh()->SendNavigate(0, url2
);
2755 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetURL());
2756 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetVirtualURL());
2758 // We should not replace the pending entry for an error URL.
2759 navigator
->DidStartProvisionalLoad(main_test_rfh(), 1, -1, true, url1
);
2760 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
2761 navigator
->DidStartProvisionalLoad(
2762 main_test_rfh(), 1, -1, true, GURL(kUnreachableWebDataURL
));
2763 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
2765 // We should remember if the pending entry will replace the current one.
2766 // http://crbug.com/308444.
2767 navigator
->DidStartProvisionalLoad(main_test_rfh(), 1, -1, true, url1
);
2768 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2769 set_should_replace_entry(true);
2770 navigator
->DidStartProvisionalLoad(main_test_rfh(), 1, -1, true, url2
);
2772 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2773 should_replace_entry());
2774 // TODO(nasko): Until OnNavigate is moved to RenderFrameHost, we need
2775 // to go through the RenderViewHost. The TestRenderViewHost routes navigations
2776 // to the main frame.
2777 test_rvh()->SendNavigate(0, url2
);
2778 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetURL());
2781 // Tests that the URLs for renderer-initiated navigations are not displayed to
2782 // the user until the navigation commits, to prevent URL spoof attacks.
2783 // See http://crbug.com/99016.
2784 TEST_F(NavigationControllerTest
, DontShowRendererURLUntilCommit
) {
2785 NavigationControllerImpl
& controller
= controller_impl();
2786 TestNotificationTracker notifications
;
2787 RegisterForAllNavNotifications(¬ifications
, &controller
);
2789 const GURL
url0("http://foo/0");
2790 const GURL
url1("http://foo/1");
2792 // For typed navigations (browser-initiated), both pending and visible entries
2793 // should update before commit.
2794 controller
.LoadURL(url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2795 EXPECT_EQ(url0
, controller
.GetPendingEntry()->GetURL());
2796 EXPECT_EQ(url0
, controller
.GetVisibleEntry()->GetURL());
2797 test_rvh()->SendNavigate(0, url0
);
2799 // For link clicks (renderer-initiated navigations), the pending entry should
2800 // update before commit but the visible should not.
2801 NavigationController::LoadURLParams
load_url_params(url1
);
2802 load_url_params
.is_renderer_initiated
= true;
2803 controller
.LoadURLWithParams(load_url_params
);
2804 EXPECT_EQ(url0
, controller
.GetVisibleEntry()->GetURL());
2805 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
2807 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2808 is_renderer_initiated());
2810 // After commit, both visible should be updated, there should be no pending
2811 // entry, and we should no longer treat the entry as renderer-initiated.
2812 test_rvh()->SendNavigate(1, url1
);
2813 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2814 EXPECT_FALSE(controller
.GetPendingEntry());
2816 NavigationEntryImpl::FromNavigationEntry(
2817 controller
.GetLastCommittedEntry())->is_renderer_initiated());
2819 notifications
.Reset();
2822 // Tests that the URLs for renderer-initiated navigations in new tabs are
2823 // displayed to the user before commit, as long as the initial about:blank
2824 // page has not been modified. If so, we must revert to showing about:blank.
2825 // See http://crbug.com/9682.
2826 TEST_F(NavigationControllerTest
, ShowRendererURLInNewTabUntilModified
) {
2827 NavigationControllerImpl
& controller
= controller_impl();
2828 TestNotificationTracker notifications
;
2829 RegisterForAllNavNotifications(¬ifications
, &controller
);
2831 const GURL
url("http://foo");
2833 // For renderer-initiated navigations in new tabs (with no committed entries),
2834 // we show the pending entry's URL as long as the about:blank page is not
2836 NavigationController::LoadURLParams
load_url_params(url
);
2837 load_url_params
.transition_type
= PAGE_TRANSITION_LINK
;
2838 load_url_params
.is_renderer_initiated
= true;
2839 controller
.LoadURLWithParams(load_url_params
);
2840 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
2841 EXPECT_EQ(url
, controller
.GetPendingEntry()->GetURL());
2843 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2844 is_renderer_initiated());
2845 EXPECT_TRUE(controller
.IsInitialNavigation());
2846 EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
2848 // There should be no title yet.
2849 EXPECT_TRUE(contents()->GetTitle().empty());
2851 // If something else modifies the contents of the about:blank page, then
2852 // we must revert to showing about:blank to avoid a URL spoof.
2853 test_rvh()->OnMessageReceived(
2854 ViewHostMsg_DidAccessInitialDocument(0));
2855 EXPECT_TRUE(test_rvh()->has_accessed_initial_document());
2856 EXPECT_FALSE(controller
.GetVisibleEntry());
2857 EXPECT_EQ(url
, controller
.GetPendingEntry()->GetURL());
2859 notifications
.Reset();
2862 TEST_F(NavigationControllerTest
, DontShowRendererURLInNewTabAfterCommit
) {
2863 NavigationControllerImpl
& controller
= controller_impl();
2864 TestNotificationTracker notifications
;
2865 RegisterForAllNavNotifications(¬ifications
, &controller
);
2867 const GURL
url1("http://foo/eh");
2868 const GURL
url2("http://foo/bee");
2870 // For renderer-initiated navigations in new tabs (with no committed entries),
2871 // we show the pending entry's URL as long as the about:blank page is not
2873 NavigationController::LoadURLParams
load_url_params(url1
);
2874 load_url_params
.transition_type
= PAGE_TRANSITION_LINK
;
2875 load_url_params
.is_renderer_initiated
= true;
2876 controller
.LoadURLWithParams(load_url_params
);
2877 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2879 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2880 is_renderer_initiated());
2881 EXPECT_TRUE(controller
.IsInitialNavigation());
2882 EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
2884 // Simulate a commit and then starting a new pending navigation.
2885 test_rvh()->SendNavigate(0, url1
);
2886 NavigationController::LoadURLParams
load_url2_params(url2
);
2887 load_url2_params
.transition_type
= PAGE_TRANSITION_LINK
;
2888 load_url2_params
.is_renderer_initiated
= true;
2889 controller
.LoadURLWithParams(load_url2_params
);
2891 // We should not consider this an initial navigation, and thus should
2892 // not show the pending URL.
2893 EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
2894 EXPECT_FALSE(controller
.IsInitialNavigation());
2895 EXPECT_TRUE(controller
.GetVisibleEntry());
2896 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2898 notifications
.Reset();
2901 // Tests that IsInPageNavigation returns appropriate results. Prevents
2902 // regression for bug 1126349.
2903 TEST_F(NavigationControllerTest
, IsInPageNavigation
) {
2904 NavigationControllerImpl
& controller
= controller_impl();
2905 // Navigate to URL with no refs.
2906 const GURL
url("http://www.google.com/home.html");
2907 test_rvh()->SendNavigate(0, url
);
2909 // Reloading the page is not an in-page navigation.
2910 EXPECT_FALSE(controller
.IsURLInPageNavigation(url
));
2911 const GURL
other_url("http://www.google.com/add.html");
2912 EXPECT_FALSE(controller
.IsURLInPageNavigation(other_url
));
2913 const GURL
url_with_ref("http://www.google.com/home.html#my_ref");
2914 EXPECT_TRUE(controller
.IsURLInPageNavigation(url_with_ref
));
2916 // Navigate to URL with refs.
2917 test_rvh()->SendNavigate(1, url_with_ref
);
2919 // Reloading the page is not an in-page navigation.
2920 EXPECT_FALSE(controller
.IsURLInPageNavigation(url_with_ref
));
2921 EXPECT_FALSE(controller
.IsURLInPageNavigation(url
));
2922 EXPECT_FALSE(controller
.IsURLInPageNavigation(other_url
));
2923 const GURL
other_url_with_ref("http://www.google.com/home.html#my_other_ref");
2924 EXPECT_TRUE(controller
.IsURLInPageNavigation(other_url_with_ref
));
2926 // Going to the same url again will be considered in-page
2927 // if the renderer says it is even if the navigation type isn't IN_PAGE.
2928 EXPECT_TRUE(controller
.IsURLInPageNavigation(url_with_ref
, true,
2929 NAVIGATION_TYPE_UNKNOWN
));
2931 // Going back to the non ref url will be considered in-page if the navigation
2933 EXPECT_TRUE(controller
.IsURLInPageNavigation(url
, true,
2934 NAVIGATION_TYPE_IN_PAGE
));
2937 // Some pages can have subframes with the same base URL (minus the reference) as
2938 // the main page. Even though this is hard, it can happen, and we don't want
2939 // these subframe navigations to affect the toplevel document. They should
2940 // instead be ignored. http://crbug.com/5585
2941 TEST_F(NavigationControllerTest
, SameSubframe
) {
2942 NavigationControllerImpl
& controller
= controller_impl();
2943 // Navigate the main frame.
2944 const GURL
url("http://www.google.com/");
2945 test_rvh()->SendNavigate(0, url
);
2947 // We should be at the first navigation entry.
2948 EXPECT_EQ(controller
.GetEntryCount(), 1);
2949 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
2951 // Navigate a subframe that would normally count as in-page.
2952 const GURL
subframe("http://www.google.com/#");
2953 ViewHostMsg_FrameNavigate_Params params
;
2955 params
.url
= subframe
;
2956 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
2957 params
.should_update_history
= false;
2958 params
.gesture
= NavigationGestureAuto
;
2959 params
.is_post
= false;
2960 params
.page_state
= PageState::CreateFromURL(subframe
);
2961 LoadCommittedDetails details
;
2962 EXPECT_FALSE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
2964 // Nothing should have changed.
2965 EXPECT_EQ(controller
.GetEntryCount(), 1);
2966 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
2969 // Make sure that on cloning a WebContentsImpl and going back needs_reload is
2971 TEST_F(NavigationControllerTest
, CloneAndGoBack
) {
2972 NavigationControllerImpl
& controller
= controller_impl();
2973 const GURL
url1("http://foo1");
2974 const GURL
url2("http://foo2");
2975 const base::string16
title(base::ASCIIToUTF16("Title"));
2977 NavigateAndCommit(url1
);
2978 controller
.GetVisibleEntry()->SetTitle(title
);
2979 NavigateAndCommit(url2
);
2981 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
2983 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
2984 EXPECT_TRUE(clone
->GetController().NeedsReload());
2985 clone
->GetController().GoBack();
2986 // Navigating back should have triggered needs_reload_ to go false.
2987 EXPECT_FALSE(clone
->GetController().NeedsReload());
2989 // Ensure that the pending URL and its title are visible.
2990 EXPECT_EQ(url1
, clone
->GetController().GetVisibleEntry()->GetURL());
2991 EXPECT_EQ(title
, clone
->GetTitle());
2994 // Make sure that reloading a cloned tab doesn't change its pending entry index.
2995 // See http://crbug.com/234491.
2996 TEST_F(NavigationControllerTest
, CloneAndReload
) {
2997 NavigationControllerImpl
& controller
= controller_impl();
2998 const GURL
url1("http://foo1");
2999 const GURL
url2("http://foo2");
3000 const base::string16
title(base::ASCIIToUTF16("Title"));
3002 NavigateAndCommit(url1
);
3003 controller
.GetVisibleEntry()->SetTitle(title
);
3004 NavigateAndCommit(url2
);
3006 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
3007 clone
->GetController().LoadIfNecessary();
3009 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
3010 EXPECT_EQ(1, clone
->GetController().GetPendingEntryIndex());
3012 clone
->GetController().Reload(true);
3013 EXPECT_EQ(1, clone
->GetController().GetPendingEntryIndex());
3016 // Make sure that cloning a WebContentsImpl doesn't copy interstitials.
3017 TEST_F(NavigationControllerTest
, CloneOmitsInterstitials
) {
3018 NavigationControllerImpl
& controller
= controller_impl();
3019 const GURL
url1("http://foo1");
3020 const GURL
url2("http://foo2");
3022 NavigateAndCommit(url1
);
3023 NavigateAndCommit(url2
);
3025 // Add an interstitial entry. Should be deleted with controller.
3026 NavigationEntryImpl
* interstitial_entry
= new NavigationEntryImpl();
3027 interstitial_entry
->set_page_type(PAGE_TYPE_INTERSTITIAL
);
3028 controller
.SetTransientEntry(interstitial_entry
);
3030 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
3032 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
3035 // Test requesting and triggering a lazy reload.
3036 TEST_F(NavigationControllerTest
, LazyReload
) {
3037 NavigationControllerImpl
& controller
= controller_impl();
3038 const GURL
url("http://foo");
3039 NavigateAndCommit(url
);
3040 ASSERT_FALSE(controller
.NeedsReload());
3042 // Request a reload to happen when the controller becomes active (e.g. after
3043 // the renderer gets killed in background on Android).
3044 controller
.SetNeedsReload();
3045 ASSERT_TRUE(controller
.NeedsReload());
3047 // Set the controller as active, triggering the requested reload.
3048 controller
.SetActive(true);
3049 ASSERT_FALSE(controller
.NeedsReload());
3052 // Tests a subframe navigation while a toplevel navigation is pending.
3053 // http://crbug.com/43967
3054 TEST_F(NavigationControllerTest
, SubframeWhilePending
) {
3055 NavigationControllerImpl
& controller
= controller_impl();
3056 // Load the first page.
3057 const GURL
url1("http://foo/");
3058 NavigateAndCommit(url1
);
3060 // Now start a pending load to a totally different page, but don't commit it.
3061 const GURL
url2("http://bar/");
3063 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
3065 // Send a subframe update from the first page, as if one had just
3066 // automatically loaded. Auto subframes don't increment the page ID.
3067 const GURL
url1_sub("http://foo/subframe");
3068 ViewHostMsg_FrameNavigate_Params params
;
3069 params
.page_id
= controller
.GetLastCommittedEntry()->GetPageID();
3070 params
.url
= url1_sub
;
3071 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
3072 params
.should_update_history
= false;
3073 params
.gesture
= NavigationGestureAuto
;
3074 params
.is_post
= false;
3075 params
.page_state
= PageState::CreateFromURL(url1_sub
);
3076 LoadCommittedDetails details
;
3078 // This should return false meaning that nothing was actually updated.
3079 EXPECT_FALSE(controller
.RendererDidNavigate(test_rvh(), params
, &details
));
3081 // The notification should have updated the last committed one, and not
3082 // the pending load.
3083 EXPECT_EQ(url1
, controller
.GetLastCommittedEntry()->GetURL());
3085 // The active entry should be unchanged by the subframe load.
3086 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
3089 // Test CopyStateFrom with 2 urls, the first selected and nothing in the target.
3090 TEST_F(NavigationControllerTest
, CopyStateFrom
) {
3091 NavigationControllerImpl
& controller
= controller_impl();
3092 const GURL
url1("http://foo1");
3093 const GURL
url2("http://foo2");
3095 NavigateAndCommit(url1
);
3096 NavigateAndCommit(url2
);
3097 controller
.GoBack();
3098 contents()->CommitPendingNavigation();
3100 scoped_ptr
<TestWebContents
> other_contents(
3101 static_cast<TestWebContents
*>(CreateTestWebContents()));
3102 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3103 other_controller
.CopyStateFrom(controller
);
3105 // other_controller should now contain 2 urls.
3106 ASSERT_EQ(2, other_controller
.GetEntryCount());
3107 // We should be looking at the first one.
3108 ASSERT_EQ(0, other_controller
.GetCurrentEntryIndex());
3110 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3111 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
3112 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3113 // This is a different site than url1, so the IDs start again at 0.
3114 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(1)->GetPageID());
3116 // The max page ID map should be copied over and updated with the max page ID
3117 // from the current tab.
3118 SiteInstance
* instance1
=
3119 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0));
3120 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3122 // Ensure the SessionStorageNamespaceMaps are the same size and have
3123 // the same partitons loaded.
3125 // TODO(ajwong): We should load a url from a different partition earlier
3126 // to make sure this map has more than one entry.
3127 const SessionStorageNamespaceMap
& session_storage_namespace_map
=
3128 controller
.GetSessionStorageNamespaceMap();
3129 const SessionStorageNamespaceMap
& other_session_storage_namespace_map
=
3130 other_controller
.GetSessionStorageNamespaceMap();
3131 EXPECT_EQ(session_storage_namespace_map
.size(),
3132 other_session_storage_namespace_map
.size());
3133 for (SessionStorageNamespaceMap::const_iterator it
=
3134 session_storage_namespace_map
.begin();
3135 it
!= session_storage_namespace_map
.end();
3137 SessionStorageNamespaceMap::const_iterator other
=
3138 other_session_storage_namespace_map
.find(it
->first
);
3139 EXPECT_TRUE(other
!= other_session_storage_namespace_map
.end());
3143 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
3144 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune
) {
3145 NavigationControllerImpl
& controller
= controller_impl();
3146 const GURL
url1("http://foo/1");
3147 const GURL
url2("http://foo/2");
3148 const GURL
url3("http://foo/3");
3150 NavigateAndCommit(url1
);
3151 NavigateAndCommit(url2
);
3153 // First two entries should have the same SiteInstance.
3154 SiteInstance
* instance1
=
3155 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(0));
3156 SiteInstance
* instance2
=
3157 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(1));
3158 EXPECT_EQ(instance1
, instance2
);
3159 EXPECT_EQ(0, controller
.GetEntryAtIndex(0)->GetPageID());
3160 EXPECT_EQ(1, controller
.GetEntryAtIndex(1)->GetPageID());
3161 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1
));
3163 scoped_ptr
<TestWebContents
> other_contents(
3164 static_cast<TestWebContents
*>(CreateTestWebContents()));
3165 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3166 other_contents
->NavigateAndCommit(url3
);
3167 other_contents
->ExpectSetHistoryLengthAndPrune(
3168 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3169 other_controller
.GetEntryAtIndex(0)->GetPageID());
3170 other_controller
.CopyStateFromAndPrune(&controller
, false);
3172 // other_controller should now contain the 3 urls: url1, url2 and url3.
3174 ASSERT_EQ(3, other_controller
.GetEntryCount());
3176 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3178 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3179 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3180 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
3181 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
3182 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(1)->GetPageID());
3183 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3185 // A new SiteInstance in a different BrowsingInstance should be used for the
3187 SiteInstance
* instance3
=
3188 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
3189 EXPECT_NE(instance3
, instance1
);
3190 EXPECT_FALSE(instance3
->IsRelatedSiteInstance(instance1
));
3192 // The max page ID map should be copied over and updated with the max page ID
3193 // from the current tab.
3194 EXPECT_EQ(1, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3195 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance3
));
3198 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry in
3200 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune2
) {
3201 NavigationControllerImpl
& controller
= controller_impl();
3202 const GURL
url1("http://foo1");
3203 const GURL
url2("http://foo2");
3204 const GURL
url3("http://foo3");
3206 NavigateAndCommit(url1
);
3207 NavigateAndCommit(url2
);
3208 controller
.GoBack();
3209 contents()->CommitPendingNavigation();
3211 scoped_ptr
<TestWebContents
> other_contents(
3212 static_cast<TestWebContents
*>(CreateTestWebContents()));
3213 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3214 other_contents
->NavigateAndCommit(url3
);
3215 other_contents
->ExpectSetHistoryLengthAndPrune(
3216 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 1,
3217 other_controller
.GetEntryAtIndex(0)->GetPageID());
3218 other_controller
.CopyStateFromAndPrune(&controller
, false);
3220 // other_controller should now contain: url1, url3
3222 ASSERT_EQ(2, other_controller
.GetEntryCount());
3223 ASSERT_EQ(1, other_controller
.GetCurrentEntryIndex());
3225 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3226 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3227 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(1)->GetPageID());
3229 // The max page ID map should be copied over and updated with the max page ID
3230 // from the current tab.
3231 SiteInstance
* instance1
=
3232 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(1));
3233 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3236 // Test CopyStateFromAndPrune with 2 urls, the last selected and 2 entries in
3238 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune3
) {
3239 NavigationControllerImpl
& controller
= controller_impl();
3240 const GURL
url1("http://foo1");
3241 const GURL
url2("http://foo2");
3242 const GURL
url3("http://foo3");
3243 const GURL
url4("http://foo4");
3245 NavigateAndCommit(url1
);
3246 NavigateAndCommit(url2
);
3248 scoped_ptr
<TestWebContents
> other_contents(
3249 static_cast<TestWebContents
*>(CreateTestWebContents()));
3250 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3251 other_contents
->NavigateAndCommit(url3
);
3252 other_contents
->NavigateAndCommit(url4
);
3253 other_contents
->ExpectSetHistoryLengthAndPrune(
3254 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(1)), 2,
3255 other_controller
.GetEntryAtIndex(0)->GetPageID());
3256 other_controller
.CopyStateFromAndPrune(&controller
, false);
3258 // other_controller should now contain: url1, url2, url4
3260 ASSERT_EQ(3, other_controller
.GetEntryCount());
3261 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3263 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3264 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3265 EXPECT_EQ(url4
, other_controller
.GetEntryAtIndex(2)->GetURL());
3267 // The max page ID map should be copied over and updated with the max page ID
3268 // from the current tab.
3269 SiteInstance
* instance1
=
3270 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
3271 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3274 // Test CopyStateFromAndPrune with 2 urls, 2 entries in the target, with
3275 // not the last entry selected in the target.
3276 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneNotLast
) {
3277 NavigationControllerImpl
& controller
= controller_impl();
3278 const GURL
url1("http://foo1");
3279 const GURL
url2("http://foo2");
3280 const GURL
url3("http://foo3");
3281 const GURL
url4("http://foo4");
3283 NavigateAndCommit(url1
);
3284 NavigateAndCommit(url2
);
3286 scoped_ptr
<TestWebContents
> other_contents(
3287 static_cast<TestWebContents
*>(CreateTestWebContents()));
3288 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3289 other_contents
->NavigateAndCommit(url3
);
3290 other_contents
->NavigateAndCommit(url4
);
3291 other_controller
.GoBack();
3292 other_contents
->CommitPendingNavigation();
3293 other_contents
->ExpectSetHistoryLengthAndPrune(
3294 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3295 other_controller
.GetEntryAtIndex(0)->GetPageID());
3296 other_controller
.CopyStateFromAndPrune(&controller
, false);
3298 // other_controller should now contain: url1, url2, url3
3300 ASSERT_EQ(3, other_controller
.GetEntryCount());
3301 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3303 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3304 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3305 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
3307 // The max page ID map should be copied over and updated with the max page ID
3308 // from the current tab.
3309 SiteInstance
* instance1
=
3310 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
3311 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3314 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry plus
3315 // a pending entry in the target.
3316 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneTargetPending
) {
3317 NavigationControllerImpl
& controller
= controller_impl();
3318 const GURL
url1("http://foo1");
3319 const GURL
url2("http://foo2");
3320 const GURL
url3("http://foo3");
3321 const GURL
url4("http://foo4");
3323 NavigateAndCommit(url1
);
3324 NavigateAndCommit(url2
);
3325 controller
.GoBack();
3326 contents()->CommitPendingNavigation();
3328 scoped_ptr
<TestWebContents
> other_contents(
3329 static_cast<TestWebContents
*>(CreateTestWebContents()));
3330 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3331 other_contents
->NavigateAndCommit(url3
);
3332 other_controller
.LoadURL(
3333 url4
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
3334 other_contents
->ExpectSetHistoryLengthAndPrune(
3335 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 1,
3336 other_controller
.GetEntryAtIndex(0)->GetPageID());
3337 other_controller
.CopyStateFromAndPrune(&controller
, false);
3339 // other_controller should now contain url1, url3, and a pending entry
3342 ASSERT_EQ(2, other_controller
.GetEntryCount());
3343 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
3345 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3346 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3348 // And there should be a pending entry for url4.
3349 ASSERT_TRUE(other_controller
.GetPendingEntry());
3350 EXPECT_EQ(url4
, other_controller
.GetPendingEntry()->GetURL());
3352 // The max page ID map should be copied over and updated with the max page ID
3353 // from the current tab.
3354 SiteInstance
* instance1
=
3355 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0));
3356 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3359 // Test CopyStateFromAndPrune with 1 url in the source, 1 entry and a pending
3360 // client redirect entry (with the same page ID) in the target. This used to
3361 // crash because the last committed entry would be pruned but max_page_id
3362 // remembered the page ID (http://crbug.com/234809).
3363 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneTargetPending2
) {
3364 NavigationControllerImpl
& controller
= controller_impl();
3365 const GURL
url1("http://foo1");
3366 const GURL
url2a("http://foo2/a");
3367 const GURL
url2b("http://foo2/b");
3369 NavigateAndCommit(url1
);
3371 scoped_ptr
<TestWebContents
> other_contents(
3372 static_cast<TestWebContents
*>(CreateTestWebContents()));
3373 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3374 other_contents
->NavigateAndCommit(url2a
);
3375 // Simulate a client redirect, which has the same page ID as entry 2a.
3376 other_controller
.LoadURL(
3377 url2b
, Referrer(), PAGE_TRANSITION_LINK
, std::string());
3378 other_controller
.GetPendingEntry()->SetPageID(
3379 other_controller
.GetLastCommittedEntry()->GetPageID());
3381 other_contents
->ExpectSetHistoryLengthAndPrune(
3382 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 1,
3383 other_controller
.GetEntryAtIndex(0)->GetPageID());
3384 other_controller
.CopyStateFromAndPrune(&controller
, false);
3386 // other_controller should now contain url1, url2a, and a pending entry
3389 ASSERT_EQ(2, other_controller
.GetEntryCount());
3390 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
3392 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3393 EXPECT_EQ(url2a
, other_controller
.GetEntryAtIndex(1)->GetURL());
3395 // And there should be a pending entry for url4.
3396 ASSERT_TRUE(other_controller
.GetPendingEntry());
3397 EXPECT_EQ(url2b
, other_controller
.GetPendingEntry()->GetURL());
3399 // Let the pending entry commit.
3400 other_contents
->CommitPendingNavigation();
3402 // The max page ID map should be copied over and updated with the max page ID
3403 // from the current tab.
3404 SiteInstance
* instance1
=
3405 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(1));
3406 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3409 // Test CopyStateFromAndPrune with 2 urls, a back navigation pending in the
3410 // source, and 1 entry in the target. The back pending entry should be ignored.
3411 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneSourcePending
) {
3412 NavigationControllerImpl
& controller
= controller_impl();
3413 const GURL
url1("http://foo1");
3414 const GURL
url2("http://foo2");
3415 const GURL
url3("http://foo3");
3417 NavigateAndCommit(url1
);
3418 NavigateAndCommit(url2
);
3419 controller
.GoBack();
3421 scoped_ptr
<TestWebContents
> other_contents(
3422 static_cast<TestWebContents
*>(CreateTestWebContents()));
3423 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3424 other_contents
->NavigateAndCommit(url3
);
3425 other_contents
->ExpectSetHistoryLengthAndPrune(
3426 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3427 other_controller
.GetEntryAtIndex(0)->GetPageID());
3428 other_controller
.CopyStateFromAndPrune(&controller
, false);
3430 // other_controller should now contain: url1, url2, url3
3432 ASSERT_EQ(3, other_controller
.GetEntryCount());
3433 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3435 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3436 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3437 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
3438 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3440 // The max page ID map should be copied over and updated with the max page ID
3441 // from the current tab.
3442 SiteInstance
* instance1
=
3443 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
3444 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3447 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest,
3448 // when the max entry count is 3. We should prune one entry.
3449 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneMaxEntries
) {
3450 NavigationControllerImpl
& controller
= controller_impl();
3451 size_t original_count
= NavigationControllerImpl::max_entry_count();
3452 const int kMaxEntryCount
= 3;
3454 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
3456 const GURL
url1("http://foo/1");
3457 const GURL
url2("http://foo/2");
3458 const GURL
url3("http://foo/3");
3459 const GURL
url4("http://foo/4");
3461 // Create a PrunedListener to observe prune notifications.
3462 PrunedListener
listener(&controller
);
3464 NavigateAndCommit(url1
);
3465 NavigateAndCommit(url2
);
3466 NavigateAndCommit(url3
);
3468 scoped_ptr
<TestWebContents
> other_contents(
3469 static_cast<TestWebContents
*>(CreateTestWebContents()));
3470 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3471 other_contents
->NavigateAndCommit(url4
);
3472 other_contents
->ExpectSetHistoryLengthAndPrune(
3473 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3474 other_controller
.GetEntryAtIndex(0)->GetPageID());
3475 other_controller
.CopyStateFromAndPrune(&controller
, false);
3477 // We should have received a pruned notification.
3478 EXPECT_EQ(1, listener
.notification_count_
);
3479 EXPECT_TRUE(listener
.details_
.from_front
);
3480 EXPECT_EQ(1, listener
.details_
.count
);
3482 // other_controller should now contain only 3 urls: url2, url3 and url4.
3484 ASSERT_EQ(3, other_controller
.GetEntryCount());
3486 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3488 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(0)->GetURL());
3489 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3490 EXPECT_EQ(url4
, other_controller
.GetEntryAtIndex(2)->GetURL());
3491 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(0)->GetPageID());
3492 EXPECT_EQ(2, other_controller
.GetEntryAtIndex(1)->GetPageID());
3493 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3495 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
3498 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest, with
3499 // replace_entry set to true.
3500 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneReplaceEntry
) {
3501 NavigationControllerImpl
& controller
= controller_impl();
3502 const GURL
url1("http://foo/1");
3503 const GURL
url2("http://foo/2");
3504 const GURL
url3("http://foo/3");
3506 NavigateAndCommit(url1
);
3507 NavigateAndCommit(url2
);
3509 // First two entries should have the same SiteInstance.
3510 SiteInstance
* instance1
=
3511 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(0));
3512 SiteInstance
* instance2
=
3513 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(1));
3514 EXPECT_EQ(instance1
, instance2
);
3515 EXPECT_EQ(0, controller
.GetEntryAtIndex(0)->GetPageID());
3516 EXPECT_EQ(1, controller
.GetEntryAtIndex(1)->GetPageID());
3517 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1
));
3519 scoped_ptr
<TestWebContents
> other_contents(
3520 static_cast<TestWebContents
*>(CreateTestWebContents()));
3521 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3522 other_contents
->NavigateAndCommit(url3
);
3523 other_contents
->ExpectSetHistoryLengthAndPrune(
3524 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 1,
3525 other_controller
.GetEntryAtIndex(0)->GetPageID());
3526 other_controller
.CopyStateFromAndPrune(&controller
, true);
3528 // other_controller should now contain the 2 urls: url1 and url3.
3530 ASSERT_EQ(2, other_controller
.GetEntryCount());
3532 ASSERT_EQ(1, other_controller
.GetCurrentEntryIndex());
3534 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3535 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3536 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
3537 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(1)->GetPageID());
3539 // A new SiteInstance in a different BrowsingInstance should be used for the
3541 SiteInstance
* instance3
=
3542 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(1));
3543 EXPECT_NE(instance3
, instance1
);
3544 EXPECT_FALSE(instance3
->IsRelatedSiteInstance(instance1
));
3546 // The max page ID map should be copied over and updated with the max page ID
3547 // from the current tab.
3548 EXPECT_EQ(1, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3549 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance3
));
3552 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest, when the max
3553 // entry count is 3 and replace_entry is true. We should not prune entries.
3554 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneMaxEntriesReplaceEntry
) {
3555 NavigationControllerImpl
& controller
= controller_impl();
3556 size_t original_count
= NavigationControllerImpl::max_entry_count();
3557 const int kMaxEntryCount
= 3;
3559 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
3561 const GURL
url1("http://foo/1");
3562 const GURL
url2("http://foo/2");
3563 const GURL
url3("http://foo/3");
3564 const GURL
url4("http://foo/4");
3566 // Create a PrunedListener to observe prune notifications.
3567 PrunedListener
listener(&controller
);
3569 NavigateAndCommit(url1
);
3570 NavigateAndCommit(url2
);
3571 NavigateAndCommit(url3
);
3573 scoped_ptr
<TestWebContents
> other_contents(
3574 static_cast<TestWebContents
*>(CreateTestWebContents()));
3575 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3576 other_contents
->NavigateAndCommit(url4
);
3577 other_contents
->ExpectSetHistoryLengthAndPrune(
3578 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3579 other_controller
.GetEntryAtIndex(0)->GetPageID());
3580 other_controller
.CopyStateFromAndPrune(&controller
, true);
3582 // We should have received no pruned notification.
3583 EXPECT_EQ(0, listener
.notification_count_
);
3585 // other_controller should now contain only 3 urls: url1, url2 and url4.
3587 ASSERT_EQ(3, other_controller
.GetEntryCount());
3589 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3591 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3592 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3593 EXPECT_EQ(url4
, other_controller
.GetEntryAtIndex(2)->GetURL());
3594 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
3595 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(1)->GetPageID());
3596 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3598 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
3601 // Tests that navigations initiated from the page (with the history object)
3602 // work as expected without navigation entries.
3603 TEST_F(NavigationControllerTest
, HistoryNavigate
) {
3604 NavigationControllerImpl
& controller
= controller_impl();
3605 const GURL
url1("http://foo/1");
3606 const GURL
url2("http://foo/2");
3607 const GURL
url3("http://foo/3");
3609 NavigateAndCommit(url1
);
3610 NavigateAndCommit(url2
);
3611 NavigateAndCommit(url3
);
3612 controller
.GoBack();
3613 contents()->CommitPendingNavigation();
3615 // Simulate the page calling history.back(), it should not create a pending
3617 contents()->OnGoToEntryAtOffset(-1);
3618 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3619 // The actual cross-navigation is suspended until the current RVH tells us
3620 // it unloaded, simulate that.
3621 contents()->ProceedWithCrossSiteNavigation();
3622 // Also make sure we told the page to navigate.
3623 const IPC::Message
* message
=
3624 process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID
);
3625 ASSERT_TRUE(message
!= NULL
);
3626 Tuple1
<ViewMsg_Navigate_Params
> nav_params
;
3627 ViewMsg_Navigate::Read(message
, &nav_params
);
3628 EXPECT_EQ(url1
, nav_params
.a
.url
);
3629 process()->sink().ClearMessages();
3631 // Now test history.forward()
3632 contents()->OnGoToEntryAtOffset(1);
3633 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3634 // The actual cross-navigation is suspended until the current RVH tells us
3635 // it unloaded, simulate that.
3636 contents()->ProceedWithCrossSiteNavigation();
3637 message
= process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID
);
3638 ASSERT_TRUE(message
!= NULL
);
3639 ViewMsg_Navigate::Read(message
, &nav_params
);
3640 EXPECT_EQ(url3
, nav_params
.a
.url
);
3641 process()->sink().ClearMessages();
3643 // Make sure an extravagant history.go() doesn't break.
3644 contents()->OnGoToEntryAtOffset(120); // Out of bounds.
3645 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3646 message
= process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID
);
3647 EXPECT_TRUE(message
== NULL
);
3650 // Test call to PruneAllButLastCommitted for the only entry.
3651 TEST_F(NavigationControllerTest
, PruneAllButLastCommittedForSingle
) {
3652 NavigationControllerImpl
& controller
= controller_impl();
3653 const GURL
url1("http://foo1");
3654 NavigateAndCommit(url1
);
3656 contents()->ExpectSetHistoryLengthAndPrune(
3657 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(0)), 0,
3658 controller
.GetEntryAtIndex(0)->GetPageID());
3660 controller
.PruneAllButLastCommitted();
3662 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3663 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url1
);
3666 // Test call to PruneAllButLastCommitted for first entry.
3667 TEST_F(NavigationControllerTest
, PruneAllButLastCommittedForFirst
) {
3668 NavigationControllerImpl
& controller
= controller_impl();
3669 const GURL
url1("http://foo/1");
3670 const GURL
url2("http://foo/2");
3671 const GURL
url3("http://foo/3");
3673 NavigateAndCommit(url1
);
3674 NavigateAndCommit(url2
);
3675 NavigateAndCommit(url3
);
3676 controller
.GoBack();
3677 controller
.GoBack();
3678 contents()->CommitPendingNavigation();
3680 contents()->ExpectSetHistoryLengthAndPrune(
3681 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(0)), 0,
3682 controller
.GetEntryAtIndex(0)->GetPageID());
3684 controller
.PruneAllButLastCommitted();
3686 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3687 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url1
);
3690 // Test call to PruneAllButLastCommitted for intermediate entry.
3691 TEST_F(NavigationControllerTest
, PruneAllButLastCommittedForIntermediate
) {
3692 NavigationControllerImpl
& controller
= controller_impl();
3693 const GURL
url1("http://foo/1");
3694 const GURL
url2("http://foo/2");
3695 const GURL
url3("http://foo/3");
3697 NavigateAndCommit(url1
);
3698 NavigateAndCommit(url2
);
3699 NavigateAndCommit(url3
);
3700 controller
.GoBack();
3701 contents()->CommitPendingNavigation();
3703 contents()->ExpectSetHistoryLengthAndPrune(
3704 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(1)), 0,
3705 controller
.GetEntryAtIndex(1)->GetPageID());
3707 controller
.PruneAllButLastCommitted();
3709 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3710 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url2
);
3713 // Test call to PruneAllButLastCommitted for a pending entry that is not yet in
3714 // the list of entries.
3715 TEST_F(NavigationControllerTest
, PruneAllButLastCommittedForPendingNotInList
) {
3716 NavigationControllerImpl
& controller
= controller_impl();
3717 const GURL
url1("http://foo/1");
3718 const GURL
url2("http://foo/2");
3719 const GURL
url3("http://foo/3");
3721 NavigateAndCommit(url1
);
3722 NavigateAndCommit(url2
);
3724 // Create a pending entry that is not in the entry list.
3726 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
3727 EXPECT_TRUE(controller
.GetPendingEntry());
3728 EXPECT_EQ(2, controller
.GetEntryCount());
3730 contents()->ExpectSetHistoryLengthAndPrune(
3731 NULL
, 0, controller
.GetPendingEntry()->GetPageID());
3732 controller
.PruneAllButLastCommitted();
3734 // We should only have the last committed and pending entries at this point,
3735 // and the pending entry should still not be in the entry list.
3736 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
3737 EXPECT_EQ(url2
, controller
.GetEntryAtIndex(0)->GetURL());
3738 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3739 EXPECT_TRUE(controller
.GetPendingEntry());
3740 EXPECT_EQ(1, controller
.GetEntryCount());
3742 // Try to commit the pending entry.
3743 test_rvh()->SendNavigate(2, url3
);
3744 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3745 EXPECT_FALSE(controller
.GetPendingEntry());
3746 EXPECT_EQ(2, controller
.GetEntryCount());
3747 EXPECT_EQ(url3
, controller
.GetEntryAtIndex(1)->GetURL());
3750 // Test to ensure that when we do a history navigation back to the current
3751 // committed page (e.g., going forward to a slow-loading page, then pressing
3752 // the back button), we just stop the navigation to prevent the throbber from
3753 // running continuously. Otherwise, the RenderViewHost forces the throbber to
3754 // start, but WebKit essentially ignores the navigation and never sends a
3755 // message to stop the throbber.
3756 TEST_F(NavigationControllerTest
, StopOnHistoryNavigationToCurrentPage
) {
3757 NavigationControllerImpl
& controller
= controller_impl();
3758 const GURL
url0("http://foo/0");
3759 const GURL
url1("http://foo/1");
3761 NavigateAndCommit(url0
);
3762 NavigateAndCommit(url1
);
3764 // Go back to the original page, then forward to the slow page, then back
3765 controller
.GoBack();
3766 contents()->CommitPendingNavigation();
3768 controller
.GoForward();
3769 EXPECT_EQ(1, controller
.GetPendingEntryIndex());
3771 controller
.GoBack();
3772 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3775 TEST_F(NavigationControllerTest
, IsInitialNavigation
) {
3776 NavigationControllerImpl
& controller
= controller_impl();
3777 TestNotificationTracker notifications
;
3778 RegisterForAllNavNotifications(¬ifications
, &controller
);
3781 EXPECT_TRUE(controller
.IsInitialNavigation());
3783 // After commit, it stays false.
3784 const GURL
url1("http://foo1");
3785 test_rvh()->SendNavigate(0, url1
);
3786 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
3787 navigation_entry_committed_counter_
= 0;
3788 EXPECT_FALSE(controller
.IsInitialNavigation());
3790 // After starting a new navigation, it stays false.
3791 const GURL
url2("http://foo2");
3793 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
3796 // Check that the favicon is not reused across a client redirect.
3797 // (crbug.com/28515)
3798 TEST_F(NavigationControllerTest
, ClearFaviconOnRedirect
) {
3799 const GURL
kPageWithFavicon("http://withfavicon.html");
3800 const GURL
kPageWithoutFavicon("http://withoutfavicon.html");
3801 const GURL
kIconURL("http://withfavicon.ico");
3802 const gfx::Image kDefaultFavicon
= FaviconStatus().image
;
3804 NavigationControllerImpl
& controller
= controller_impl();
3805 TestNotificationTracker notifications
;
3806 RegisterForAllNavNotifications(¬ifications
, &controller
);
3808 test_rvh()->SendNavigate(0, kPageWithFavicon
);
3809 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
3810 navigation_entry_committed_counter_
= 0;
3812 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
3814 EXPECT_EQ(kPageWithFavicon
, entry
->GetURL());
3816 // Simulate Chromium having set the favicon for |kPageWithFavicon|.
3817 content::FaviconStatus
& favicon_status
= entry
->GetFavicon();
3818 favicon_status
.image
= CreateImage(SK_ColorWHITE
);
3819 favicon_status
.url
= kIconURL
;
3820 favicon_status
.valid
= true;
3821 EXPECT_FALSE(DoImagesMatch(kDefaultFavicon
, entry
->GetFavicon().image
));
3823 test_rvh()->SendNavigateWithTransition(
3825 kPageWithoutFavicon
,
3826 PAGE_TRANSITION_CLIENT_REDIRECT
);
3827 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
3828 navigation_entry_committed_counter_
= 0;
3830 entry
= controller
.GetLastCommittedEntry();
3832 EXPECT_EQ(kPageWithoutFavicon
, entry
->GetURL());
3834 EXPECT_TRUE(DoImagesMatch(kDefaultFavicon
, entry
->GetFavicon().image
));
3837 // Check that the favicon is not cleared for NavigationEntries which were
3838 // previously navigated to.
3839 TEST_F(NavigationControllerTest
, BackNavigationDoesNotClearFavicon
) {
3840 const GURL
kUrl1("http://www.a.com/1");
3841 const GURL
kUrl2("http://www.a.com/2");
3842 const GURL
kIconURL("http://www.a.com/1/favicon.ico");
3844 NavigationControllerImpl
& controller
= controller_impl();
3845 TestNotificationTracker notifications
;
3846 RegisterForAllNavNotifications(¬ifications
, &controller
);
3848 test_rvh()->SendNavigate(0, kUrl1
);
3849 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
3850 navigation_entry_committed_counter_
= 0;
3852 // Simulate Chromium having set the favicon for |kUrl1|.
3853 gfx::Image favicon_image
= CreateImage(SK_ColorWHITE
);
3854 content::NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
3856 content::FaviconStatus
& favicon_status
= entry
->GetFavicon();
3857 favicon_status
.image
= favicon_image
;
3858 favicon_status
.url
= kIconURL
;
3859 favicon_status
.valid
= true;
3861 // Navigate to another page and go back to the original page.
3862 test_rvh()->SendNavigate(1, kUrl2
);
3863 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
3864 navigation_entry_committed_counter_
= 0;
3865 test_rvh()->SendNavigateWithTransition(
3868 PAGE_TRANSITION_FORWARD_BACK
);
3869 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
3870 navigation_entry_committed_counter_
= 0;
3872 // Verify that the favicon for the page at |kUrl1| was not cleared.
3873 entry
= controller
.GetEntryAtIndex(0);
3875 EXPECT_EQ(kUrl1
, entry
->GetURL());
3876 EXPECT_TRUE(DoImagesMatch(favicon_image
, entry
->GetFavicon().image
));
3879 // The test crashes on android: http://crbug.com/170449
3880 #if defined(OS_ANDROID)
3881 #define MAYBE_PurgeScreenshot DISABLED_PurgeScreenshot
3883 #define MAYBE_PurgeScreenshot PurgeScreenshot
3885 // Tests that screenshot are purged correctly.
3886 TEST_F(NavigationControllerTest
, MAYBE_PurgeScreenshot
) {
3887 NavigationControllerImpl
& controller
= controller_impl();
3889 NavigationEntryImpl
* entry
;
3891 // Navigate enough times to make sure that some screenshots are purged.
3892 for (int i
= 0; i
< 12; ++i
) {
3893 const GURL
url(base::StringPrintf("http://foo%d/", i
));
3894 NavigateAndCommit(url
);
3895 EXPECT_EQ(i
, controller
.GetCurrentEntryIndex());
3898 MockScreenshotManager
* screenshot_manager
=
3899 new MockScreenshotManager(&controller
);
3900 controller
.SetScreenshotManager(screenshot_manager
);
3901 for (int i
= 0; i
< controller
.GetEntryCount(); ++i
) {
3902 entry
= NavigationEntryImpl::FromNavigationEntry(
3903 controller
.GetEntryAtIndex(i
));
3904 screenshot_manager
->TakeScreenshotFor(entry
);
3905 EXPECT_TRUE(entry
->screenshot().get());
3908 NavigateAndCommit(GURL("https://foo/"));
3909 EXPECT_EQ(13, controller
.GetEntryCount());
3910 entry
= NavigationEntryImpl::FromNavigationEntry(
3911 controller
.GetEntryAtIndex(11));
3912 screenshot_manager
->TakeScreenshotFor(entry
);
3914 for (int i
= 0; i
< 2; ++i
) {
3915 entry
= NavigationEntryImpl::FromNavigationEntry(
3916 controller
.GetEntryAtIndex(i
));
3917 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
3921 for (int i
= 2; i
< controller
.GetEntryCount() - 1; ++i
) {
3922 entry
= NavigationEntryImpl::FromNavigationEntry(
3923 controller
.GetEntryAtIndex(i
));
3924 EXPECT_TRUE(entry
->screenshot().get()) << "Screenshot not found for " << i
;
3927 // Navigate to index 5 and then try to assign screenshot to all entries.
3928 controller
.GoToIndex(5);
3929 contents()->CommitPendingNavigation();
3930 EXPECT_EQ(5, controller
.GetCurrentEntryIndex());
3931 for (int i
= 0; i
< controller
.GetEntryCount() - 1; ++i
) {
3932 entry
= NavigationEntryImpl::FromNavigationEntry(
3933 controller
.GetEntryAtIndex(i
));
3934 screenshot_manager
->TakeScreenshotFor(entry
);
3937 for (int i
= 10; i
<= 12; ++i
) {
3938 entry
= NavigationEntryImpl::FromNavigationEntry(
3939 controller
.GetEntryAtIndex(i
));
3940 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
3942 screenshot_manager
->TakeScreenshotFor(entry
);
3945 // Navigate to index 7 and assign screenshot to all entries.
3946 controller
.GoToIndex(7);
3947 contents()->CommitPendingNavigation();
3948 EXPECT_EQ(7, controller
.GetCurrentEntryIndex());
3949 for (int i
= 0; i
< controller
.GetEntryCount() - 1; ++i
) {
3950 entry
= NavigationEntryImpl::FromNavigationEntry(
3951 controller
.GetEntryAtIndex(i
));
3952 screenshot_manager
->TakeScreenshotFor(entry
);
3955 for (int i
= 0; i
< 2; ++i
) {
3956 entry
= NavigationEntryImpl::FromNavigationEntry(
3957 controller
.GetEntryAtIndex(i
));
3958 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
3962 // Clear all screenshots.
3963 EXPECT_EQ(13, controller
.GetEntryCount());
3964 EXPECT_EQ(10, screenshot_manager
->GetScreenshotCount());
3965 controller
.ClearAllScreenshots();
3966 EXPECT_EQ(0, screenshot_manager
->GetScreenshotCount());
3967 for (int i
= 0; i
< controller
.GetEntryCount(); ++i
) {
3968 entry
= NavigationEntryImpl::FromNavigationEntry(
3969 controller
.GetEntryAtIndex(i
));
3970 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
3975 // Test that the navigation controller clears its session history when a
3976 // navigation commits with the clear history list flag set.
3977 TEST_F(NavigationControllerTest
, ClearHistoryList
) {
3978 const GURL
url1("http://foo1");
3979 const GURL
url2("http://foo2");
3980 const GURL
url3("http://foo3");
3981 const GURL
url4("http://foo4");
3983 NavigationControllerImpl
& controller
= controller_impl();
3985 // Create a session history with three entries, second entry is active.
3986 NavigateAndCommit(url1
);
3987 NavigateAndCommit(url2
);
3988 NavigateAndCommit(url3
);
3989 controller
.GoBack();
3990 contents()->CommitPendingNavigation();
3991 EXPECT_EQ(3, controller
.GetEntryCount());
3992 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
3994 // Create a new pending navigation, and indicate that the session history
3995 // should be cleared.
3996 NavigationController::LoadURLParams
params(url4
);
3997 params
.should_clear_history_list
= true;
3998 controller
.LoadURLWithParams(params
);
4000 // Verify that the pending entry correctly indicates that the session history
4001 // should be cleared.
4002 NavigationEntryImpl
* entry
=
4003 NavigationEntryImpl::FromNavigationEntry(
4004 controller
.GetPendingEntry());
4006 EXPECT_TRUE(entry
->should_clear_history_list());
4008 // Assume that the RV correctly cleared its history and commit the navigation.
4009 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost())->
4010 set_simulate_history_list_was_cleared(true);
4011 contents()->CommitPendingNavigation();
4013 // Verify that the NavigationController's session history was correctly
4015 EXPECT_EQ(1, controller
.GetEntryCount());
4016 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
4017 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
4018 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
4019 EXPECT_FALSE(controller
.CanGoBack());
4020 EXPECT_FALSE(controller
.CanGoForward());
4021 EXPECT_EQ(url4
, controller
.GetVisibleEntry()->GetURL());
4024 } // namespace content