1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
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 // These are only used for commented out tests. If someone wants to enable
15 // them, they should be moved to chrome first.
16 // #include "chrome/browser/history/history_service.h"
17 // #include "chrome/browser/profiles/profile_manager.h"
18 // #include "chrome/browser/sessions/session_service.h"
19 // #include "chrome/browser/sessions/session_service_factory.h"
20 // #include "chrome/browser/sessions/session_service_test_helper.h"
21 // #include "chrome/browser/sessions/session_types.h"
22 #include "content/browser/renderer_host/test_render_view_host.h"
23 #include "content/browser/site_instance_impl.h"
24 #include "content/browser/web_contents/navigation_controller_impl.h"
25 #include "content/browser/web_contents/navigation_entry_impl.h"
26 #include "content/browser/web_contents/web_contents_impl.h"
27 #include "content/browser/web_contents/web_contents_screenshot_manager.h"
28 #include "content/common/view_messages.h"
29 #include "content/public/browser/navigation_details.h"
30 #include "content/public/browser/notification_registrar.h"
31 #include "content/public/browser/notification_types.h"
32 #include "content/public/browser/render_view_host.h"
33 #include "content/public/browser/render_view_host_observer.h"
34 #include "content/public/browser/web_contents_delegate.h"
35 #include "content/public/browser/web_contents_observer.h"
36 #include "content/public/common/page_state.h"
37 #include "content/public/common/url_constants.h"
38 #include "content/public/test/mock_render_process_host.h"
39 #include "content/public/test/test_notification_tracker.h"
40 #include "content/public/test/test_utils.h"
41 #include "content/test/test_web_contents.h"
42 #include "net/base/net_util.h"
43 #include "skia/ext/platform_canvas.h"
44 #include "testing/gtest/include/gtest/gtest.h"
50 // Creates an image with a 1x1 SkBitmap of the specified |color|.
51 gfx::Image
CreateImage(SkColor color
) {
53 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 1, 1);
55 bitmap
.eraseColor(color
);
56 return gfx::Image::CreateFrom1xBitmap(bitmap
);
59 // Returns true if images |a| and |b| have the same pixel data.
60 bool DoImagesMatch(const gfx::Image
& a
, const gfx::Image
& b
) {
61 // Assume that if the 1x bitmaps match, the images match.
62 SkBitmap a_bitmap
= a
.AsBitmap();
63 SkBitmap b_bitmap
= b
.AsBitmap();
65 if (a_bitmap
.width() != b_bitmap
.width() ||
66 a_bitmap
.height() != b_bitmap
.height()) {
69 SkAutoLockPixels
a_bitmap_lock(a_bitmap
);
70 SkAutoLockPixels
b_bitmap_lock(b_bitmap
);
71 return memcmp(a_bitmap
.getPixels(),
73 a_bitmap
.getSize()) == 0;
76 class MockScreenshotManager
: public content::WebContentsScreenshotManager
{
78 explicit MockScreenshotManager(content::NavigationControllerImpl
* owner
)
79 : content::WebContentsScreenshotManager(owner
),
80 encoding_screenshot_in_progress_(false) {
83 virtual ~MockScreenshotManager() {
86 void TakeScreenshotFor(content::NavigationEntryImpl
* entry
) {
88 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 1, 1);
90 bitmap
.eraseRGB(0, 0, 0);
91 encoding_screenshot_in_progress_
= true;
92 OnScreenshotTaken(entry
->GetUniqueID(), true, bitmap
);
93 WaitUntilScreenshotIsReady();
96 int GetScreenshotCount() {
97 return content::WebContentsScreenshotManager::GetScreenshotCount();
100 void WaitUntilScreenshotIsReady() {
101 if (!encoding_screenshot_in_progress_
)
103 message_loop_runner_
= new content::MessageLoopRunner
;
104 message_loop_runner_
->Run();
108 // Overridden from content::WebContentsScreenshotManager:
109 virtual void TakeScreenshotImpl(
110 content::RenderViewHost
* host
,
111 content::NavigationEntryImpl
* entry
) OVERRIDE
{
114 virtual void OnScreenshotSet(content::NavigationEntryImpl
* entry
) OVERRIDE
{
115 encoding_screenshot_in_progress_
= false;
116 WebContentsScreenshotManager::OnScreenshotSet(entry
);
117 if (message_loop_runner_
.get())
118 message_loop_runner_
->Quit();
121 scoped_refptr
<content::MessageLoopRunner
> message_loop_runner_
;
122 bool encoding_screenshot_in_progress_
;
124 DISALLOW_COPY_AND_ASSIGN(MockScreenshotManager
);
131 // TimeSmoother tests ----------------------------------------------------------
133 // With no duplicates, GetSmoothedTime should be the identity
135 TEST(TimeSmoother
, Basic
) {
136 NavigationControllerImpl::TimeSmoother smoother
;
137 for (int64 i
= 1; i
< 1000; ++i
) {
138 base::Time t
= base::Time::FromInternalValue(i
);
139 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
143 // With a single duplicate and timestamps thereafter increasing by one
144 // microsecond, the smoothed time should always be one behind.
145 TEST(TimeSmoother
, SingleDuplicate
) {
146 NavigationControllerImpl::TimeSmoother smoother
;
147 base::Time t
= base::Time::FromInternalValue(1);
148 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
149 for (int64 i
= 1; i
< 1000; ++i
) {
150 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1);
151 t
= base::Time::FromInternalValue(i
);
152 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
156 // With k duplicates and timestamps thereafter increasing by one
157 // microsecond, the smoothed time should always be k behind.
158 TEST(TimeSmoother
, ManyDuplicates
) {
159 const int64 kNumDuplicates
= 100;
160 NavigationControllerImpl::TimeSmoother smoother
;
161 base::Time t
= base::Time::FromInternalValue(1);
162 for (int64 i
= 0; i
< kNumDuplicates
; ++i
) {
163 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1);
164 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
166 for (int64 i
= 1; i
< 1000; ++i
) {
167 base::Time expected_t
=
168 base::Time::FromInternalValue(i
+ kNumDuplicates
);
169 t
= base::Time::FromInternalValue(i
);
170 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
174 // If the clock jumps far back enough after a run of duplicates, it
175 // should immediately jump to that value.
176 TEST(TimeSmoother
, ClockBackwardsJump
) {
177 const int64 kNumDuplicates
= 100;
178 NavigationControllerImpl::TimeSmoother smoother
;
179 base::Time t
= base::Time::FromInternalValue(1000);
180 for (int64 i
= 0; i
< kNumDuplicates
; ++i
) {
181 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1000);
182 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
184 t
= base::Time::FromInternalValue(500);
185 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
188 // NavigationControllerTest ----------------------------------------------------
190 class NavigationControllerTest
191 : public RenderViewHostImplTestHarness
,
192 public WebContentsObserver
{
194 NavigationControllerTest() : navigation_entry_committed_counter_(0) {
197 virtual void SetUp() OVERRIDE
{
198 RenderViewHostImplTestHarness::SetUp();
199 WebContents
* web_contents
= RenderViewHostImplTestHarness::web_contents();
200 ASSERT_TRUE(web_contents
); // The WebContents should be created by now.
201 WebContentsObserver::Observe(web_contents
);
204 // WebContentsObserver:
205 virtual void NavigationEntryCommitted(
206 const LoadCommittedDetails
& load_details
) OVERRIDE
{
207 navigation_entry_committed_counter_
++;
210 NavigationControllerImpl
& controller_impl() {
211 return static_cast<NavigationControllerImpl
&>(controller());
215 size_t navigation_entry_committed_counter_
;
218 void RegisterForAllNavNotifications(TestNotificationTracker
* tracker
,
219 NavigationController
* controller
) {
220 tracker
->ListenFor(NOTIFICATION_NAV_LIST_PRUNED
,
221 Source
<NavigationController
>(controller
));
222 tracker
->ListenFor(NOTIFICATION_NAV_ENTRY_CHANGED
,
223 Source
<NavigationController
>(controller
));
226 SiteInstance
* GetSiteInstanceFromEntry(NavigationEntry
* entry
) {
227 return NavigationEntryImpl::FromNavigationEntry(entry
)->site_instance();
230 class TestWebContentsDelegate
: public WebContentsDelegate
{
232 explicit TestWebContentsDelegate() :
233 navigation_state_change_count_(0) {}
235 int navigation_state_change_count() {
236 return navigation_state_change_count_
;
239 // Keep track of whether the tab has notified us of a navigation state change.
240 virtual void NavigationStateChanged(const WebContents
* source
,
241 unsigned changed_flags
) OVERRIDE
{
242 navigation_state_change_count_
++;
246 // The number of times NavigationStateChanged has been called.
247 int navigation_state_change_count_
;
250 // -----------------------------------------------------------------------------
252 TEST_F(NavigationControllerTest
, Defaults
) {
253 NavigationControllerImpl
& controller
= controller_impl();
255 EXPECT_FALSE(controller
.GetPendingEntry());
256 EXPECT_FALSE(controller
.GetActiveEntry());
257 EXPECT_FALSE(controller
.GetVisibleEntry());
258 EXPECT_FALSE(controller
.GetLastCommittedEntry());
259 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
260 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), -1);
261 EXPECT_EQ(controller
.GetEntryCount(), 0);
262 EXPECT_FALSE(controller
.CanGoBack());
263 EXPECT_FALSE(controller
.CanGoForward());
266 TEST_F(NavigationControllerTest
, GoToOffset
) {
267 NavigationControllerImpl
& controller
= controller_impl();
268 TestNotificationTracker notifications
;
269 RegisterForAllNavNotifications(¬ifications
, &controller
);
271 const int kNumUrls
= 5;
272 std::vector
<GURL
> urls(kNumUrls
);
273 for (int i
= 0; i
< kNumUrls
; ++i
) {
274 urls
[i
] = GURL(base::StringPrintf("http://www.a.com/%d", i
));
277 test_rvh()->SendNavigate(0, urls
[0]);
278 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
279 navigation_entry_committed_counter_
= 0;
280 EXPECT_EQ(urls
[0], controller
.GetActiveEntry()->GetVirtualURL());
281 EXPECT_FALSE(controller
.CanGoBack());
282 EXPECT_FALSE(controller
.CanGoForward());
283 EXPECT_FALSE(controller
.CanGoToOffset(1));
285 for (int i
= 1; i
<= 4; ++i
) {
286 test_rvh()->SendNavigate(i
, urls
[i
]);
287 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
288 navigation_entry_committed_counter_
= 0;
289 EXPECT_EQ(urls
[i
], controller
.GetActiveEntry()->GetVirtualURL());
290 EXPECT_TRUE(controller
.CanGoToOffset(-i
));
291 EXPECT_FALSE(controller
.CanGoToOffset(-(i
+ 1)));
292 EXPECT_FALSE(controller
.CanGoToOffset(1));
295 // We have loaded 5 pages, and are currently at the last-loaded page.
299 GO_TO_MIDDLE_PAGE
= -2,
302 GO_TO_BEGINNING
= -2,
307 const int test_offsets
[NUM_TESTS
] = {
315 for (int test
= 0; test
< NUM_TESTS
; ++test
) {
316 int offset
= test_offsets
[test
];
317 controller
.GoToOffset(offset
);
319 // Check that the GoToOffset will land on the expected page.
320 EXPECT_EQ(urls
[url_index
], controller
.GetPendingEntry()->GetVirtualURL());
321 test_rvh()->SendNavigate(url_index
, urls
[url_index
]);
322 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
323 navigation_entry_committed_counter_
= 0;
324 // Check that we can go to any valid offset into the history.
325 for (size_t j
= 0; j
< urls
.size(); ++j
)
326 EXPECT_TRUE(controller
.CanGoToOffset(j
- url_index
));
327 // Check that we can't go beyond the beginning or end of the history.
328 EXPECT_FALSE(controller
.CanGoToOffset(-(url_index
+ 1)));
329 EXPECT_FALSE(controller
.CanGoToOffset(urls
.size() - url_index
));
333 TEST_F(NavigationControllerTest
, LoadURL
) {
334 NavigationControllerImpl
& controller
= controller_impl();
335 TestNotificationTracker notifications
;
336 RegisterForAllNavNotifications(¬ifications
, &controller
);
338 const GURL
url1("http://foo1");
339 const GURL
url2("http://foo2");
341 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
342 // Creating a pending notification should not have issued any of the
343 // notifications we're listening for.
344 EXPECT_EQ(0U, notifications
.size());
346 // The load should now be pending.
347 EXPECT_EQ(controller
.GetEntryCount(), 0);
348 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), -1);
349 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
350 EXPECT_FALSE(controller
.GetLastCommittedEntry());
351 ASSERT_TRUE(controller
.GetPendingEntry());
352 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetActiveEntry());
353 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetVisibleEntry());
354 EXPECT_FALSE(controller
.CanGoBack());
355 EXPECT_FALSE(controller
.CanGoForward());
356 EXPECT_EQ(contents()->GetMaxPageID(), -1);
358 // Neither the timestamp nor the status code should have been set yet.
359 EXPECT_TRUE(controller
.GetPendingEntry()->GetTimestamp().is_null());
360 EXPECT_EQ(0, controller
.GetPendingEntry()->GetHttpStatusCode());
362 // We should have gotten no notifications from the preceeding checks.
363 EXPECT_EQ(0U, notifications
.size());
365 test_rvh()->SendNavigate(0, url1
);
366 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
367 navigation_entry_committed_counter_
= 0;
369 // The load should now be committed.
370 EXPECT_EQ(controller
.GetEntryCount(), 1);
371 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
372 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
373 EXPECT_TRUE(controller
.GetLastCommittedEntry());
374 EXPECT_FALSE(controller
.GetPendingEntry());
375 ASSERT_TRUE(controller
.GetActiveEntry());
376 EXPECT_EQ(controller
.GetActiveEntry(), controller
.GetVisibleEntry());
377 EXPECT_FALSE(controller
.CanGoBack());
378 EXPECT_FALSE(controller
.CanGoForward());
379 EXPECT_EQ(contents()->GetMaxPageID(), 0);
380 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
381 controller
.GetLastCommittedEntry())->bindings());
383 // The timestamp should have been set.
384 EXPECT_FALSE(controller
.GetActiveEntry()->GetTimestamp().is_null());
387 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
389 // The load should now be pending.
390 EXPECT_EQ(controller
.GetEntryCount(), 1);
391 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
392 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
393 EXPECT_TRUE(controller
.GetLastCommittedEntry());
394 ASSERT_TRUE(controller
.GetPendingEntry());
395 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetActiveEntry());
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
.GetActiveEntry());
419 EXPECT_EQ(controller
.GetActiveEntry(), controller
.GetVisibleEntry());
420 EXPECT_TRUE(controller
.CanGoBack());
421 EXPECT_FALSE(controller
.CanGoForward());
422 EXPECT_EQ(contents()->GetMaxPageID(), 1);
424 EXPECT_FALSE(controller
.GetActiveEntry()->GetTimestamp().is_null());
429 base::Time
GetFixedTime(base::Time time
) {
435 TEST_F(NavigationControllerTest
, LoadURLSameTime
) {
436 NavigationControllerImpl
& controller
= controller_impl();
437 TestNotificationTracker notifications
;
438 RegisterForAllNavNotifications(¬ifications
, &controller
);
440 // Set the clock to always return a timestamp of 1.
441 controller
.SetGetTimestampCallbackForTest(
442 base::Bind(&GetFixedTime
, base::Time::FromInternalValue(1)));
444 const GURL
url1("http://foo1");
445 const GURL
url2("http://foo2");
447 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
449 test_rvh()->SendNavigate(0, url1
);
450 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
451 navigation_entry_committed_counter_
= 0;
454 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
456 // Simulate the beforeunload ack for the cross-site transition, and then the
458 test_rvh()->SendShouldCloseACK(true);
459 test_rvh()->SendNavigate(1, url2
);
460 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
461 navigation_entry_committed_counter_
= 0;
463 // The two loads should now be committed.
464 ASSERT_EQ(controller
.GetEntryCount(), 2);
466 // Timestamps should be distinct despite the clock returning the
469 controller
.GetEntryAtIndex(0)->GetTimestamp().ToInternalValue());
471 controller
.GetEntryAtIndex(1)->GetTimestamp().ToInternalValue());
474 void CheckNavigationEntryMatchLoadParams(
475 NavigationController::LoadURLParams
& load_params
,
476 NavigationEntryImpl
* entry
) {
477 EXPECT_EQ(load_params
.url
, entry
->GetURL());
478 EXPECT_EQ(load_params
.referrer
.url
, entry
->GetReferrer().url
);
479 EXPECT_EQ(load_params
.referrer
.policy
, entry
->GetReferrer().policy
);
480 EXPECT_EQ(load_params
.transition_type
, entry
->GetTransitionType());
481 EXPECT_EQ(load_params
.extra_headers
, entry
->extra_headers());
483 EXPECT_EQ(load_params
.is_renderer_initiated
, entry
->is_renderer_initiated());
484 EXPECT_EQ(load_params
.base_url_for_data_url
, entry
->GetBaseURLForDataURL());
485 if (!load_params
.virtual_url_for_data_url
.is_empty()) {
486 EXPECT_EQ(load_params
.virtual_url_for_data_url
, entry
->GetVirtualURL());
488 if (NavigationController::UA_OVERRIDE_INHERIT
!=
489 load_params
.override_user_agent
) {
490 bool should_override
= (NavigationController::UA_OVERRIDE_TRUE
==
491 load_params
.override_user_agent
);
492 EXPECT_EQ(should_override
, entry
->GetIsOverridingUserAgent());
494 EXPECT_EQ(load_params
.browser_initiated_post_data
,
495 entry
->GetBrowserInitiatedPostData());
496 EXPECT_EQ(load_params
.transferred_global_request_id
,
497 entry
->transferred_global_request_id());
500 TEST_F(NavigationControllerTest
, LoadURLWithParams
) {
501 NavigationControllerImpl
& controller
= controller_impl();
503 NavigationController::LoadURLParams
load_params(GURL("http://foo"));
504 load_params
.referrer
=
505 Referrer(GURL("http://referrer"), WebKit::WebReferrerPolicyDefault
);
506 load_params
.transition_type
= PAGE_TRANSITION_GENERATED
;
507 load_params
.extra_headers
= "content-type: text/plain";
508 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
509 load_params
.is_renderer_initiated
= true;
510 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
511 load_params
.transferred_global_request_id
= GlobalRequestID(2, 3);
513 controller
.LoadURLWithParams(load_params
);
514 NavigationEntryImpl
* entry
=
515 NavigationEntryImpl::FromNavigationEntry(
516 controller
.GetPendingEntry());
518 // The timestamp should not have been set yet.
520 EXPECT_TRUE(entry
->GetTimestamp().is_null());
522 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
525 TEST_F(NavigationControllerTest
, LoadURLWithExtraParams_Data
) {
526 NavigationControllerImpl
& controller
= controller_impl();
528 NavigationController::LoadURLParams
load_params(
529 GURL("data:text/html,dataurl"));
530 load_params
.load_type
= NavigationController::LOAD_TYPE_DATA
;
531 load_params
.base_url_for_data_url
= GURL("http://foo");
532 load_params
.virtual_url_for_data_url
= GURL(kAboutBlankURL
);
533 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_FALSE
;
535 controller
.LoadURLWithParams(load_params
);
536 NavigationEntryImpl
* entry
=
537 NavigationEntryImpl::FromNavigationEntry(
538 controller
.GetPendingEntry());
540 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
543 TEST_F(NavigationControllerTest
, LoadURLWithExtraParams_HttpPost
) {
544 NavigationControllerImpl
& controller
= controller_impl();
546 NavigationController::LoadURLParams
load_params(GURL("https://posturl"));
547 load_params
.transition_type
= PAGE_TRANSITION_TYPED
;
548 load_params
.load_type
=
549 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST
;
550 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
553 const unsigned char* raw_data
=
554 reinterpret_cast<const unsigned char*>("d\n\0a2");
555 const int length
= 5;
556 std::vector
<unsigned char> post_data_vector(raw_data
, raw_data
+length
);
557 scoped_refptr
<base::RefCountedBytes
> data
=
558 base::RefCountedBytes::TakeVector(&post_data_vector
);
559 load_params
.browser_initiated_post_data
= data
.get();
561 controller
.LoadURLWithParams(load_params
);
562 NavigationEntryImpl
* entry
=
563 NavigationEntryImpl::FromNavigationEntry(
564 controller
.GetPendingEntry());
566 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
569 // Tests what happens when the same page is loaded again. Should not create a
570 // new session history entry. This is what happens when you press enter in the
571 // URL bar to reload: a pending entry is created and then it is discarded when
572 // the load commits (because WebCore didn't actually make a new entry).
573 TEST_F(NavigationControllerTest
, LoadURL_SamePage
) {
574 NavigationControllerImpl
& controller
= controller_impl();
575 TestNotificationTracker notifications
;
576 RegisterForAllNavNotifications(¬ifications
, &controller
);
578 const GURL
url1("http://foo1");
580 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
581 EXPECT_EQ(0U, notifications
.size());
582 test_rvh()->SendNavigate(0, url1
);
583 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
584 navigation_entry_committed_counter_
= 0;
586 ASSERT_TRUE(controller
.GetActiveEntry());
587 const base::Time timestamp
= controller
.GetActiveEntry()->GetTimestamp();
588 EXPECT_FALSE(timestamp
.is_null());
590 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
591 EXPECT_EQ(0U, notifications
.size());
592 test_rvh()->SendNavigate(0, url1
);
593 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
594 navigation_entry_committed_counter_
= 0;
596 // We should not have produced a new session history entry.
597 EXPECT_EQ(controller
.GetEntryCount(), 1);
598 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
599 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
600 EXPECT_TRUE(controller
.GetLastCommittedEntry());
601 EXPECT_FALSE(controller
.GetPendingEntry());
602 ASSERT_TRUE(controller
.GetActiveEntry());
603 EXPECT_FALSE(controller
.CanGoBack());
604 EXPECT_FALSE(controller
.CanGoForward());
606 // The timestamp should have been updated.
608 // TODO(akalin): Change this EXPECT_GE (and other similar ones) to
609 // EXPECT_GT once we guarantee that timestamps are unique.
610 EXPECT_GE(controller
.GetActiveEntry()->GetTimestamp(), timestamp
);
613 // Tests loading a URL but discarding it before the load commits.
614 TEST_F(NavigationControllerTest
, LoadURL_Discarded
) {
615 NavigationControllerImpl
& controller
= controller_impl();
616 TestNotificationTracker notifications
;
617 RegisterForAllNavNotifications(¬ifications
, &controller
);
619 const GURL
url1("http://foo1");
620 const GURL
url2("http://foo2");
622 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
623 EXPECT_EQ(0U, notifications
.size());
624 test_rvh()->SendNavigate(0, url1
);
625 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
626 navigation_entry_committed_counter_
= 0;
628 ASSERT_TRUE(controller
.GetActiveEntry());
629 const base::Time timestamp
= controller
.GetActiveEntry()->GetTimestamp();
630 EXPECT_FALSE(timestamp
.is_null());
632 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
633 controller
.DiscardNonCommittedEntries();
634 EXPECT_EQ(0U, notifications
.size());
636 // Should not have produced a new session history entry.
637 EXPECT_EQ(controller
.GetEntryCount(), 1);
638 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
639 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
640 EXPECT_TRUE(controller
.GetLastCommittedEntry());
641 EXPECT_FALSE(controller
.GetPendingEntry());
642 ASSERT_TRUE(controller
.GetActiveEntry());
643 EXPECT_FALSE(controller
.CanGoBack());
644 EXPECT_FALSE(controller
.CanGoForward());
646 // Timestamp should not have changed.
647 EXPECT_EQ(timestamp
, controller
.GetActiveEntry()->GetTimestamp());
650 // Tests navigations that come in unrequested. This happens when the user
651 // navigates from the web page, and here we test that there is no pending entry.
652 TEST_F(NavigationControllerTest
, LoadURL_NoPending
) {
653 NavigationControllerImpl
& controller
= controller_impl();
654 TestNotificationTracker notifications
;
655 RegisterForAllNavNotifications(¬ifications
, &controller
);
657 // First make an existing committed entry.
658 const GURL
kExistingURL1("http://eh");
660 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
661 test_rvh()->SendNavigate(0, kExistingURL1
);
662 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
663 navigation_entry_committed_counter_
= 0;
665 // Do a new navigation without making a pending one.
666 const GURL
kNewURL("http://see");
667 test_rvh()->SendNavigate(99, kNewURL
);
669 // There should no longer be any pending entry, and the third navigation we
670 // just made should be committed.
671 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
672 navigation_entry_committed_counter_
= 0;
673 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
674 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
675 EXPECT_EQ(kNewURL
, controller
.GetActiveEntry()->GetURL());
678 // Tests navigating to a new URL when there is a new pending navigation that is
679 // not the one that just loaded. This will happen if the user types in a URL to
680 // somewhere slow, and then navigates the current page before the typed URL
682 TEST_F(NavigationControllerTest
, LoadURL_NewPending
) {
683 NavigationControllerImpl
& controller
= controller_impl();
684 TestNotificationTracker notifications
;
685 RegisterForAllNavNotifications(¬ifications
, &controller
);
687 // First make an existing committed entry.
688 const GURL
kExistingURL1("http://eh");
690 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
691 test_rvh()->SendNavigate(0, kExistingURL1
);
692 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
693 navigation_entry_committed_counter_
= 0;
695 // Make a pending entry to somewhere new.
696 const GURL
kExistingURL2("http://bee");
698 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
699 EXPECT_EQ(0U, notifications
.size());
701 // After the beforeunload but before it commits, do a new navigation.
702 test_rvh()->SendShouldCloseACK(true);
703 const GURL
kNewURL("http://see");
704 static_cast<TestRenderViewHost
*>(
705 contents()->GetPendingRenderViewHost())->SendNavigate(3, kNewURL
);
707 // There should no longer be any pending entry, and the third navigation we
708 // just made should be committed.
709 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
710 navigation_entry_committed_counter_
= 0;
711 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
712 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
713 EXPECT_EQ(kNewURL
, controller
.GetActiveEntry()->GetURL());
716 // Tests navigating to a new URL when there is a pending back/forward
717 // navigation. This will happen if the user hits back, but before that commits,
718 // they navigate somewhere new.
719 TEST_F(NavigationControllerTest
, LoadURL_ExistingPending
) {
720 NavigationControllerImpl
& controller
= controller_impl();
721 TestNotificationTracker notifications
;
722 RegisterForAllNavNotifications(¬ifications
, &controller
);
724 // First make some history.
725 const GURL
kExistingURL1("http://foo/eh");
727 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
728 test_rvh()->SendNavigate(0, kExistingURL1
);
729 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
730 navigation_entry_committed_counter_
= 0;
732 const GURL
kExistingURL2("http://foo/bee");
734 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
735 test_rvh()->SendNavigate(1, kExistingURL2
);
736 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
737 navigation_entry_committed_counter_
= 0;
739 // Now make a pending back/forward navigation. The zeroth entry should be
742 EXPECT_EQ(0U, notifications
.size());
743 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
744 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
746 // Before that commits, do a new navigation.
747 const GURL
kNewURL("http://foo/see");
748 LoadCommittedDetails details
;
749 test_rvh()->SendNavigate(3, kNewURL
);
751 // There should no longer be any pending entry, and the third navigation we
752 // just made should be committed.
753 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
754 navigation_entry_committed_counter_
= 0;
755 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
756 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
757 EXPECT_EQ(kNewURL
, controller
.GetActiveEntry()->GetURL());
760 // Tests navigating to a new URL when there is a pending back/forward
761 // navigation to a cross-process, privileged URL. This will happen if the user
762 // hits back, but before that commits, they navigate somewhere new.
763 TEST_F(NavigationControllerTest
, LoadURL_PrivilegedPending
) {
764 NavigationControllerImpl
& controller
= controller_impl();
765 TestNotificationTracker notifications
;
766 RegisterForAllNavNotifications(¬ifications
, &controller
);
768 // First make some history, starting with a privileged URL.
769 const GURL
kExistingURL1("http://privileged");
771 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
772 // Pretend it has bindings so we can tell if we incorrectly copy it.
773 test_rvh()->AllowBindings(2);
774 test_rvh()->SendNavigate(0, kExistingURL1
);
775 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
776 navigation_entry_committed_counter_
= 0;
778 // Navigate cross-process to a second URL.
779 const GURL
kExistingURL2("http://foo/eh");
781 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
782 test_rvh()->SendShouldCloseACK(true);
783 TestRenderViewHost
* foo_rvh
= static_cast<TestRenderViewHost
*>(
784 contents()->GetPendingRenderViewHost());
785 foo_rvh
->SendNavigate(1, kExistingURL2
);
786 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
787 navigation_entry_committed_counter_
= 0;
789 // Now make a pending back/forward navigation to a privileged entry.
790 // The zeroth entry should be pending.
792 foo_rvh
->SendShouldCloseACK(true);
793 EXPECT_EQ(0U, notifications
.size());
794 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
795 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
796 EXPECT_EQ(2, NavigationEntryImpl::FromNavigationEntry(
797 controller
.GetPendingEntry())->bindings());
799 // Before that commits, do a new navigation.
800 const GURL
kNewURL("http://foo/bee");
801 LoadCommittedDetails details
;
802 foo_rvh
->SendNavigate(3, kNewURL
);
804 // There should no longer be any pending entry, and the third navigation we
805 // just made should be committed.
806 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
807 navigation_entry_committed_counter_
= 0;
808 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
809 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
810 EXPECT_EQ(kNewURL
, controller
.GetActiveEntry()->GetURL());
811 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
812 controller
.GetLastCommittedEntry())->bindings());
815 // Tests navigating to an existing URL when there is a pending new navigation.
816 // This will happen if the user enters a URL, but before that commits, the
817 // current page fires history.back().
818 TEST_F(NavigationControllerTest
, LoadURL_BackPreemptsPending
) {
819 NavigationControllerImpl
& controller
= controller_impl();
820 TestNotificationTracker notifications
;
821 RegisterForAllNavNotifications(¬ifications
, &controller
);
823 // First make some history.
824 const GURL
kExistingURL1("http://foo/eh");
826 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
827 test_rvh()->SendNavigate(0, kExistingURL1
);
828 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
829 navigation_entry_committed_counter_
= 0;
831 const GURL
kExistingURL2("http://foo/bee");
833 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
834 test_rvh()->SendNavigate(1, kExistingURL2
);
835 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
836 navigation_entry_committed_counter_
= 0;
838 // Now make a pending new navigation.
839 const GURL
kNewURL("http://foo/see");
841 kNewURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
842 EXPECT_EQ(0U, notifications
.size());
843 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
844 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
846 // Before that commits, a back navigation from the renderer commits.
847 test_rvh()->SendNavigate(0, kExistingURL1
);
849 // There should no longer be any pending entry, and the back navigation we
850 // just made should be committed.
851 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
852 navigation_entry_committed_counter_
= 0;
853 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
854 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
855 EXPECT_EQ(kExistingURL1
, controller
.GetActiveEntry()->GetURL());
858 // Tests an ignored navigation when there is a pending new navigation.
859 // This will happen if the user enters a URL, but before that commits, the
860 // current blank page reloads. See http://crbug.com/77507.
861 TEST_F(NavigationControllerTest
, LoadURL_IgnorePreemptsPending
) {
862 NavigationControllerImpl
& controller
= controller_impl();
863 TestNotificationTracker notifications
;
864 RegisterForAllNavNotifications(¬ifications
, &controller
);
866 // Set a WebContentsDelegate to listen for state changes.
867 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
868 EXPECT_FALSE(contents()->GetDelegate());
869 contents()->SetDelegate(delegate
.get());
871 // Without any navigations, the renderer starts at about:blank.
872 const GURL
kExistingURL(kAboutBlankURL
);
874 // Now make a pending new navigation.
875 const GURL
kNewURL("http://eh");
877 kNewURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
878 EXPECT_EQ(0U, notifications
.size());
879 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
880 EXPECT_TRUE(controller
.GetPendingEntry());
881 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
882 EXPECT_EQ(1, delegate
->navigation_state_change_count());
884 // Before that commits, a document.write and location.reload can cause the
885 // renderer to send a FrameNavigate with page_id -1.
886 test_rvh()->SendNavigate(-1, kExistingURL
);
888 // This should clear the pending entry and notify of a navigation state
889 // change, so that we do not keep displaying kNewURL.
890 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
891 EXPECT_FALSE(controller
.GetPendingEntry());
892 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
893 EXPECT_EQ(2, delegate
->navigation_state_change_count());
895 contents()->SetDelegate(NULL
);
898 // Tests that the pending entry state is correct after an abort.
899 // We do not want to clear the pending entry, so that the user doesn't
900 // lose a typed URL. (See http://crbug.com/9682.)
901 TEST_F(NavigationControllerTest
, LoadURL_AbortDoesntCancelPending
) {
902 NavigationControllerImpl
& controller
= controller_impl();
903 TestNotificationTracker notifications
;
904 RegisterForAllNavNotifications(¬ifications
, &controller
);
906 // Set a WebContentsDelegate to listen for state changes.
907 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
908 EXPECT_FALSE(contents()->GetDelegate());
909 contents()->SetDelegate(delegate
.get());
911 // Start with a pending new navigation.
912 const GURL
kNewURL("http://eh");
914 kNewURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
915 EXPECT_EQ(0U, notifications
.size());
916 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
917 EXPECT_TRUE(controller
.GetPendingEntry());
918 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
919 EXPECT_EQ(1, delegate
->navigation_state_change_count());
921 // It may abort before committing, if it's a download or due to a stop or
922 // a new navigation from the user.
923 ViewHostMsg_DidFailProvisionalLoadWithError_Params params
;
925 params
.is_main_frame
= true;
926 params
.error_code
= net::ERR_ABORTED
;
927 params
.error_description
= string16();
928 params
.url
= kNewURL
;
929 params
.showing_repost_interstitial
= false;
930 test_rvh()->OnMessageReceived(
931 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
934 // This should not clear the pending entry or notify of a navigation state
935 // change, so that we keep displaying kNewURL (until the user clears it).
936 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
937 EXPECT_TRUE(controller
.GetPendingEntry());
938 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
939 EXPECT_EQ(1, delegate
->navigation_state_change_count());
940 NavigationEntry
* pending_entry
= controller
.GetPendingEntry();
942 // Ensure that a reload keeps the same pending entry.
943 controller
.Reload(true);
944 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
945 EXPECT_TRUE(controller
.GetPendingEntry());
946 EXPECT_EQ(pending_entry
, controller
.GetPendingEntry());
947 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
949 contents()->SetDelegate(NULL
);
952 // Tests that the pending URL is not visible during a renderer-initiated
953 // redirect and abort. See http://crbug.com/83031.
954 TEST_F(NavigationControllerTest
, LoadURL_RedirectAbortDoesntShowPendingURL
) {
955 NavigationControllerImpl
& controller
= controller_impl();
956 TestNotificationTracker notifications
;
957 RegisterForAllNavNotifications(¬ifications
, &controller
);
959 // First make an existing committed entry.
960 const GURL
kExistingURL("http://foo/eh");
961 controller
.LoadURL(kExistingURL
, content::Referrer(),
962 content::PAGE_TRANSITION_TYPED
, std::string());
963 test_rvh()->SendNavigate(0, kExistingURL
);
964 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
965 navigation_entry_committed_counter_
= 0;
967 // Set a WebContentsDelegate to listen for state changes.
968 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
969 EXPECT_FALSE(contents()->GetDelegate());
970 contents()->SetDelegate(delegate
.get());
972 // Now make a pending new navigation, initiated by the renderer.
973 const GURL
kNewURL("http://foo/bee");
974 NavigationController::LoadURLParams
load_url_params(kNewURL
);
975 load_url_params
.transition_type
= PAGE_TRANSITION_TYPED
;
976 load_url_params
.is_renderer_initiated
= true;
977 controller
.LoadURLWithParams(load_url_params
);
978 EXPECT_EQ(0U, notifications
.size());
979 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
980 EXPECT_TRUE(controller
.GetPendingEntry());
981 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
982 EXPECT_EQ(0, delegate
->navigation_state_change_count());
984 // The visible entry should be the last committed URL, not the pending one.
985 EXPECT_EQ(kExistingURL
, controller
.GetVisibleEntry()->GetURL());
987 // Now the navigation redirects.
988 const GURL
kRedirectURL("http://foo/see");
989 test_rvh()->OnMessageReceived(
990 ViewHostMsg_DidRedirectProvisionalLoad(0, // routing_id
991 -1, // pending page_id
993 kRedirectURL
)); // new url
995 // We don't want to change the NavigationEntry's url, in case it cancels.
996 // Prevents regression of http://crbug.com/77786.
997 EXPECT_EQ(kNewURL
, controller
.GetPendingEntry()->GetURL());
999 // It may abort before committing, if it's a download or due to a stop or
1000 // a new navigation from the user.
1001 ViewHostMsg_DidFailProvisionalLoadWithError_Params params
;
1002 params
.frame_id
= 1;
1003 params
.is_main_frame
= true;
1004 params
.error_code
= net::ERR_ABORTED
;
1005 params
.error_description
= string16();
1006 params
.url
= kRedirectURL
;
1007 params
.showing_repost_interstitial
= false;
1008 test_rvh()->OnMessageReceived(
1009 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
1012 // Because the pending entry is renderer initiated and not visible, we
1013 // clear it when it fails.
1014 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1015 EXPECT_FALSE(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 // so that no spoof is possible.
1021 EXPECT_EQ(kExistingURL
, controller
.GetVisibleEntry()->GetURL());
1023 contents()->SetDelegate(NULL
);
1026 // Ensure that NavigationEntries track which bindings their RenderViewHost had
1027 // at the time they committed. http://crbug.com/173672.
1028 TEST_F(NavigationControllerTest
, LoadURL_WithBindings
) {
1029 NavigationControllerImpl
& controller
= controller_impl();
1030 TestNotificationTracker notifications
;
1031 RegisterForAllNavNotifications(¬ifications
, &controller
);
1033 const GURL
url1("http://foo1");
1034 const GURL
url2("http://foo2");
1036 // Navigate to a first, unprivileged URL.
1037 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1038 EXPECT_EQ(NavigationEntryImpl::kInvalidBindings
,
1039 NavigationEntryImpl::FromNavigationEntry(
1040 controller
.GetPendingEntry())->bindings());
1043 TestRenderViewHost
* orig_rvh
= static_cast<TestRenderViewHost
*>(test_rvh());
1044 orig_rvh
->SendNavigate(0, url1
);
1045 EXPECT_EQ(controller
.GetEntryCount(), 1);
1046 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1047 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
1048 controller
.GetLastCommittedEntry())->bindings());
1050 // Manually increase the number of active views in the SiteInstance
1051 // that orig_rvh belongs to, to prevent it from being destroyed when
1052 // it gets swapped out, so that we can reuse orig_rvh when the
1053 // controller goes back.
1054 static_cast<SiteInstanceImpl
*>(orig_rvh
->GetSiteInstance())->
1055 increment_active_view_count();
1057 // Navigate to a second URL, simulate the beforeunload ack for the cross-site
1058 // transition, and set bindings on the pending RenderViewHost to simulate a
1060 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1061 orig_rvh
->SendShouldCloseACK(true);
1062 contents()->GetPendingRenderViewHost()->AllowBindings(1);
1063 static_cast<TestRenderViewHost
*>(
1064 contents()->GetPendingRenderViewHost())->SendNavigate(1, url2
);
1066 // The second load should be committed, and bindings should be remembered.
1067 EXPECT_EQ(controller
.GetEntryCount(), 2);
1068 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1069 EXPECT_TRUE(controller
.CanGoBack());
1070 EXPECT_EQ(1, NavigationEntryImpl::FromNavigationEntry(
1071 controller
.GetLastCommittedEntry())->bindings());
1073 // Going back, the first entry should still appear unprivileged.
1074 controller
.GoBack();
1075 orig_rvh
->SendNavigate(0, url1
);
1076 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1077 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
1078 controller
.GetLastCommittedEntry())->bindings());
1081 TEST_F(NavigationControllerTest
, Reload
) {
1082 NavigationControllerImpl
& controller
= controller_impl();
1083 TestNotificationTracker notifications
;
1084 RegisterForAllNavNotifications(¬ifications
, &controller
);
1086 const GURL
url1("http://foo1");
1088 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1089 EXPECT_EQ(0U, notifications
.size());
1090 test_rvh()->SendNavigate(0, url1
);
1091 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1092 navigation_entry_committed_counter_
= 0;
1093 ASSERT_TRUE(controller
.GetActiveEntry());
1094 controller
.GetActiveEntry()->SetTitle(ASCIIToUTF16("Title"));
1095 controller
.Reload(true);
1096 EXPECT_EQ(0U, notifications
.size());
1098 const base::Time timestamp
= controller
.GetActiveEntry()->GetTimestamp();
1099 EXPECT_FALSE(timestamp
.is_null());
1101 // The reload is pending.
1102 EXPECT_EQ(controller
.GetEntryCount(), 1);
1103 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1104 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1105 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1106 EXPECT_TRUE(controller
.GetPendingEntry());
1107 EXPECT_FALSE(controller
.CanGoBack());
1108 EXPECT_FALSE(controller
.CanGoForward());
1109 // Make sure the title has been cleared (will be redrawn just after reload).
1110 // Avoids a stale cached title when the new page being reloaded has no title.
1111 // See http://crbug.com/96041.
1112 EXPECT_TRUE(controller
.GetActiveEntry()->GetTitle().empty());
1114 test_rvh()->SendNavigate(0, url1
);
1115 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1116 navigation_entry_committed_counter_
= 0;
1118 // Now the reload is committed.
1119 EXPECT_EQ(controller
.GetEntryCount(), 1);
1120 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1121 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1122 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1123 EXPECT_FALSE(controller
.GetPendingEntry());
1124 EXPECT_FALSE(controller
.CanGoBack());
1125 EXPECT_FALSE(controller
.CanGoForward());
1127 // The timestamp should have been updated.
1128 ASSERT_TRUE(controller
.GetActiveEntry());
1129 EXPECT_GE(controller
.GetActiveEntry()->GetTimestamp(), timestamp
);
1132 // Tests what happens when a reload navigation produces a new page.
1133 TEST_F(NavigationControllerTest
, Reload_GeneratesNewPage
) {
1134 NavigationControllerImpl
& controller
= controller_impl();
1135 TestNotificationTracker notifications
;
1136 RegisterForAllNavNotifications(¬ifications
, &controller
);
1138 const GURL
url1("http://foo1");
1139 const GURL
url2("http://foo2");
1141 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1142 test_rvh()->SendNavigate(0, url1
);
1143 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1144 navigation_entry_committed_counter_
= 0;
1146 controller
.Reload(true);
1147 EXPECT_EQ(0U, notifications
.size());
1149 test_rvh()->SendNavigate(1, url2
);
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(), 2);
1155 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1156 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1157 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1158 EXPECT_FALSE(controller
.GetPendingEntry());
1159 EXPECT_TRUE(controller
.CanGoBack());
1160 EXPECT_FALSE(controller
.CanGoForward());
1163 class TestNavigationObserver
: public RenderViewHostObserver
{
1165 explicit TestNavigationObserver(RenderViewHost
* render_view_host
)
1166 : RenderViewHostObserver(render_view_host
) {
1169 const GURL
& navigated_url() const {
1170 return navigated_url_
;
1174 virtual void Navigate(const GURL
& url
) OVERRIDE
{
1175 navigated_url_
= url
;
1179 GURL navigated_url_
;
1182 #if !defined(OS_ANDROID) // http://crbug.com/157428
1183 TEST_F(NavigationControllerTest
, ReloadOriginalRequestURL
) {
1184 NavigationControllerImpl
& controller
= controller_impl();
1185 TestNotificationTracker notifications
;
1186 RegisterForAllNavNotifications(¬ifications
, &controller
);
1187 TestNavigationObserver
observer(test_rvh());
1189 const GURL
original_url("http://foo1");
1190 const GURL
final_url("http://foo2");
1192 // Load up the original URL, but get redirected.
1194 original_url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1195 EXPECT_EQ(0U, notifications
.size());
1196 test_rvh()->SendNavigateWithOriginalRequestURL(0, final_url
, original_url
);
1197 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1198 navigation_entry_committed_counter_
= 0;
1200 // The NavigationEntry should save both the original URL and the final
1202 EXPECT_EQ(original_url
, controller
.GetActiveEntry()->GetOriginalRequestURL());
1203 EXPECT_EQ(final_url
, controller
.GetActiveEntry()->GetURL());
1205 // Reload using the original URL.
1206 controller
.GetActiveEntry()->SetTitle(ASCIIToUTF16("Title"));
1207 controller
.ReloadOriginalRequestURL(false);
1208 EXPECT_EQ(0U, notifications
.size());
1210 // The reload is pending. The request should point to the original URL.
1211 EXPECT_EQ(original_url
, observer
.navigated_url());
1212 EXPECT_EQ(controller
.GetEntryCount(), 1);
1213 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1214 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1215 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1216 EXPECT_TRUE(controller
.GetPendingEntry());
1217 EXPECT_FALSE(controller
.CanGoBack());
1218 EXPECT_FALSE(controller
.CanGoForward());
1220 // Make sure the title has been cleared (will be redrawn just after reload).
1221 // Avoids a stale cached title when the new page being reloaded has no title.
1222 // See http://crbug.com/96041.
1223 EXPECT_TRUE(controller
.GetActiveEntry()->GetTitle().empty());
1225 // Send that the navigation has proceeded; say it got redirected again.
1226 test_rvh()->SendNavigate(0, final_url
);
1227 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1228 navigation_entry_committed_counter_
= 0;
1230 // Now the reload is committed.
1231 EXPECT_EQ(controller
.GetEntryCount(), 1);
1232 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1233 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1234 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1235 EXPECT_FALSE(controller
.GetPendingEntry());
1236 EXPECT_FALSE(controller
.CanGoBack());
1237 EXPECT_FALSE(controller
.CanGoForward());
1240 #endif // !defined(OS_ANDROID)
1242 // Tests what happens when we navigate back successfully
1243 TEST_F(NavigationControllerTest
, Back
) {
1244 NavigationControllerImpl
& controller
= controller_impl();
1245 TestNotificationTracker notifications
;
1246 RegisterForAllNavNotifications(¬ifications
, &controller
);
1248 const GURL
url1("http://foo1");
1249 test_rvh()->SendNavigate(0, url1
);
1250 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1251 navigation_entry_committed_counter_
= 0;
1253 const GURL
url2("http://foo2");
1254 test_rvh()->SendNavigate(1, url2
);
1255 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1256 navigation_entry_committed_counter_
= 0;
1258 controller
.GoBack();
1259 EXPECT_EQ(0U, notifications
.size());
1261 // We should now have a pending navigation to go back.
1262 EXPECT_EQ(controller
.GetEntryCount(), 2);
1263 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1264 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1265 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1266 EXPECT_TRUE(controller
.GetPendingEntry());
1267 EXPECT_FALSE(controller
.CanGoBack());
1268 EXPECT_FALSE(controller
.CanGoToOffset(-1));
1269 EXPECT_TRUE(controller
.CanGoForward());
1270 EXPECT_TRUE(controller
.CanGoToOffset(1));
1271 EXPECT_FALSE(controller
.CanGoToOffset(2)); // Cannot go foward 2 steps.
1273 // Timestamp for entry 1 should be on or after that of entry 0.
1274 EXPECT_FALSE(controller
.GetEntryAtIndex(0)->GetTimestamp().is_null());
1275 EXPECT_GE(controller
.GetEntryAtIndex(1)->GetTimestamp(),
1276 controller
.GetEntryAtIndex(0)->GetTimestamp());
1278 test_rvh()->SendNavigate(0, url2
);
1279 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1280 navigation_entry_committed_counter_
= 0;
1282 // The back navigation completed successfully.
1283 EXPECT_EQ(controller
.GetEntryCount(), 2);
1284 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1285 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1286 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1287 EXPECT_FALSE(controller
.GetPendingEntry());
1288 EXPECT_FALSE(controller
.CanGoBack());
1289 EXPECT_FALSE(controller
.CanGoToOffset(-1));
1290 EXPECT_TRUE(controller
.CanGoForward());
1291 EXPECT_TRUE(controller
.CanGoToOffset(1));
1292 EXPECT_FALSE(controller
.CanGoToOffset(2)); // Cannot go foward 2 steps.
1294 // Timestamp for entry 0 should be on or after that of entry 1
1295 // (since we went back to it).
1296 EXPECT_GE(controller
.GetEntryAtIndex(0)->GetTimestamp(),
1297 controller
.GetEntryAtIndex(1)->GetTimestamp());
1300 // Tests what happens when a back navigation produces a new page.
1301 TEST_F(NavigationControllerTest
, Back_GeneratesNewPage
) {
1302 NavigationControllerImpl
& controller
= controller_impl();
1303 TestNotificationTracker notifications
;
1304 RegisterForAllNavNotifications(¬ifications
, &controller
);
1306 const GURL
url1("http://foo/1");
1307 const GURL
url2("http://foo/2");
1308 const GURL
url3("http://foo/3");
1311 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1312 test_rvh()->SendNavigate(0, url1
);
1313 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1314 navigation_entry_committed_counter_
= 0;
1316 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1317 test_rvh()->SendNavigate(1, url2
);
1318 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1319 navigation_entry_committed_counter_
= 0;
1321 controller
.GoBack();
1322 EXPECT_EQ(0U, notifications
.size());
1324 // We should now have a pending navigation to go back.
1325 EXPECT_EQ(controller
.GetEntryCount(), 2);
1326 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1327 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1328 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1329 EXPECT_TRUE(controller
.GetPendingEntry());
1330 EXPECT_FALSE(controller
.CanGoBack());
1331 EXPECT_TRUE(controller
.CanGoForward());
1333 test_rvh()->SendNavigate(2, url3
);
1334 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1335 navigation_entry_committed_counter_
= 0;
1337 // The back navigation resulted in a completely new navigation.
1338 // TODO(darin): perhaps this behavior will be confusing to users?
1339 EXPECT_EQ(controller
.GetEntryCount(), 3);
1340 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 2);
1341 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1342 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1343 EXPECT_FALSE(controller
.GetPendingEntry());
1344 EXPECT_TRUE(controller
.CanGoBack());
1345 EXPECT_FALSE(controller
.CanGoForward());
1348 // Receives a back message when there is a new pending navigation entry.
1349 TEST_F(NavigationControllerTest
, Back_NewPending
) {
1350 NavigationControllerImpl
& controller
= controller_impl();
1351 TestNotificationTracker notifications
;
1352 RegisterForAllNavNotifications(¬ifications
, &controller
);
1354 const GURL
kUrl1("http://foo1");
1355 const GURL
kUrl2("http://foo2");
1356 const GURL
kUrl3("http://foo3");
1358 // First navigate two places so we have some back history.
1359 test_rvh()->SendNavigate(0, kUrl1
);
1360 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1361 navigation_entry_committed_counter_
= 0;
1363 // controller.LoadURL(kUrl2, PAGE_TRANSITION_TYPED);
1364 test_rvh()->SendNavigate(1, kUrl2
);
1365 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1366 navigation_entry_committed_counter_
= 0;
1368 // Now start a new pending navigation and go back before it commits.
1369 controller
.LoadURL(kUrl3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1370 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1371 EXPECT_EQ(kUrl3
, controller
.GetPendingEntry()->GetURL());
1372 controller
.GoBack();
1374 // The pending navigation should now be the "back" item and the new one
1376 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
1377 EXPECT_EQ(kUrl1
, controller
.GetPendingEntry()->GetURL());
1380 // Receives a back message when there is a different renavigation already
1382 TEST_F(NavigationControllerTest
, Back_OtherBackPending
) {
1383 NavigationControllerImpl
& controller
= controller_impl();
1384 const GURL
kUrl1("http://foo/1");
1385 const GURL
kUrl2("http://foo/2");
1386 const GURL
kUrl3("http://foo/3");
1388 // First navigate three places so we have some back history.
1389 test_rvh()->SendNavigate(0, kUrl1
);
1390 test_rvh()->SendNavigate(1, kUrl2
);
1391 test_rvh()->SendNavigate(2, kUrl3
);
1393 // With nothing pending, say we get a navigation to the second entry.
1394 test_rvh()->SendNavigate(1, kUrl2
);
1396 // We know all the entries have the same site instance, so we can just grab
1397 // a random one for looking up other entries.
1398 SiteInstance
* site_instance
=
1399 NavigationEntryImpl::FromNavigationEntry(
1400 controller
.GetLastCommittedEntry())->site_instance();
1402 // That second URL should be the last committed and it should have gotten the
1404 EXPECT_EQ(kUrl2
, controller
.GetEntryWithPageID(site_instance
, 1)->GetURL());
1405 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1406 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1408 // Now go forward to the last item again and say it was committed.
1409 controller
.GoForward();
1410 test_rvh()->SendNavigate(2, kUrl3
);
1412 // Now start going back one to the second page. It will be pending.
1413 controller
.GoBack();
1414 EXPECT_EQ(1, controller
.GetPendingEntryIndex());
1415 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1417 // Not synthesize a totally new back event to the first page. This will not
1418 // match the pending one.
1419 test_rvh()->SendNavigate(0, kUrl1
);
1421 // The committed navigation should clear the pending entry.
1422 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1424 // But the navigated entry should be the last committed.
1425 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1426 EXPECT_EQ(kUrl1
, controller
.GetLastCommittedEntry()->GetURL());
1429 // Tests what happens when we navigate forward successfully.
1430 TEST_F(NavigationControllerTest
, Forward
) {
1431 NavigationControllerImpl
& controller
= controller_impl();
1432 TestNotificationTracker notifications
;
1433 RegisterForAllNavNotifications(¬ifications
, &controller
);
1435 const GURL
url1("http://foo1");
1436 const GURL
url2("http://foo2");
1438 test_rvh()->SendNavigate(0, url1
);
1439 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1440 navigation_entry_committed_counter_
= 0;
1442 test_rvh()->SendNavigate(1, url2
);
1443 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1444 navigation_entry_committed_counter_
= 0;
1446 controller
.GoBack();
1447 test_rvh()->SendNavigate(0, url1
);
1448 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1449 navigation_entry_committed_counter_
= 0;
1451 controller
.GoForward();
1453 // We should now have a pending navigation to go forward.
1454 EXPECT_EQ(controller
.GetEntryCount(), 2);
1455 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1456 EXPECT_EQ(controller
.GetPendingEntryIndex(), 1);
1457 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1458 EXPECT_TRUE(controller
.GetPendingEntry());
1459 EXPECT_TRUE(controller
.CanGoBack());
1460 EXPECT_TRUE(controller
.CanGoToOffset(-1));
1461 EXPECT_FALSE(controller
.CanGoToOffset(-2)); // Cannot go back 2 steps.
1462 EXPECT_FALSE(controller
.CanGoForward());
1463 EXPECT_FALSE(controller
.CanGoToOffset(1));
1465 // Timestamp for entry 0 should be on or after that of entry 1
1466 // (since we went back to it).
1467 EXPECT_FALSE(controller
.GetEntryAtIndex(0)->GetTimestamp().is_null());
1468 EXPECT_GE(controller
.GetEntryAtIndex(0)->GetTimestamp(),
1469 controller
.GetEntryAtIndex(1)->GetTimestamp());
1471 test_rvh()->SendNavigate(1, url2
);
1472 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1473 navigation_entry_committed_counter_
= 0;
1475 // The forward navigation completed successfully.
1476 EXPECT_EQ(controller
.GetEntryCount(), 2);
1477 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1478 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1479 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1480 EXPECT_FALSE(controller
.GetPendingEntry());
1481 EXPECT_TRUE(controller
.CanGoBack());
1482 EXPECT_TRUE(controller
.CanGoToOffset(-1));
1483 EXPECT_FALSE(controller
.CanGoToOffset(-2)); // Cannot go back 2 steps.
1484 EXPECT_FALSE(controller
.CanGoForward());
1485 EXPECT_FALSE(controller
.CanGoToOffset(1));
1487 // Timestamp for entry 1 should be on or after that of entry 0
1488 // (since we went forward to it).
1489 EXPECT_GE(controller
.GetEntryAtIndex(1)->GetTimestamp(),
1490 controller
.GetEntryAtIndex(0)->GetTimestamp());
1493 // Tests what happens when a forward navigation produces a new page.
1494 TEST_F(NavigationControllerTest
, Forward_GeneratesNewPage
) {
1495 NavigationControllerImpl
& controller
= controller_impl();
1496 TestNotificationTracker notifications
;
1497 RegisterForAllNavNotifications(¬ifications
, &controller
);
1499 const GURL
url1("http://foo1");
1500 const GURL
url2("http://foo2");
1501 const GURL
url3("http://foo3");
1503 test_rvh()->SendNavigate(0, url1
);
1504 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1505 navigation_entry_committed_counter_
= 0;
1506 test_rvh()->SendNavigate(1, url2
);
1507 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1508 navigation_entry_committed_counter_
= 0;
1510 controller
.GoBack();
1511 test_rvh()->SendNavigate(0, url1
);
1512 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1513 navigation_entry_committed_counter_
= 0;
1515 controller
.GoForward();
1516 EXPECT_EQ(0U, notifications
.size());
1518 // Should now have a pending navigation to go forward.
1519 EXPECT_EQ(controller
.GetEntryCount(), 2);
1520 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1521 EXPECT_EQ(controller
.GetPendingEntryIndex(), 1);
1522 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1523 EXPECT_TRUE(controller
.GetPendingEntry());
1524 EXPECT_TRUE(controller
.CanGoBack());
1525 EXPECT_FALSE(controller
.CanGoForward());
1527 test_rvh()->SendNavigate(2, url3
);
1528 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1529 navigation_entry_committed_counter_
= 0;
1530 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_LIST_PRUNED
));
1532 EXPECT_EQ(controller
.GetEntryCount(), 2);
1533 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1534 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1535 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1536 EXPECT_FALSE(controller
.GetPendingEntry());
1537 EXPECT_TRUE(controller
.CanGoBack());
1538 EXPECT_FALSE(controller
.CanGoForward());
1541 // Two consequent navigation for the same URL entered in should be considered
1542 // as SAME_PAGE navigation even when we are redirected to some other page.
1543 TEST_F(NavigationControllerTest
, Redirect
) {
1544 NavigationControllerImpl
& controller
= controller_impl();
1545 TestNotificationTracker notifications
;
1546 RegisterForAllNavNotifications(¬ifications
, &controller
);
1548 const GURL
url1("http://foo1");
1549 const GURL
url2("http://foo2"); // Redirection target
1552 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1554 EXPECT_EQ(0U, notifications
.size());
1555 test_rvh()->SendNavigate(0, url2
);
1556 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1557 navigation_entry_committed_counter_
= 0;
1560 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1562 EXPECT_TRUE(controller
.GetPendingEntry());
1563 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1564 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
1566 ViewHostMsg_FrameNavigate_Params params
;
1569 params
.transition
= PAGE_TRANSITION_SERVER_REDIRECT
;
1570 params
.redirects
.push_back(GURL("http://foo1"));
1571 params
.redirects
.push_back(GURL("http://foo2"));
1572 params
.should_update_history
= false;
1573 params
.gesture
= NavigationGestureAuto
;
1574 params
.is_post
= false;
1575 params
.page_state
= PageState::CreateFromURL(url2
);
1577 LoadCommittedDetails details
;
1579 EXPECT_EQ(0U, notifications
.size());
1580 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1581 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1582 navigation_entry_committed_counter_
= 0;
1584 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_SAME_PAGE
);
1585 EXPECT_EQ(controller
.GetEntryCount(), 1);
1586 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1587 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1588 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1589 EXPECT_FALSE(controller
.GetPendingEntry());
1590 EXPECT_EQ(url2
, controller
.GetActiveEntry()->GetURL());
1592 EXPECT_FALSE(controller
.CanGoBack());
1593 EXPECT_FALSE(controller
.CanGoForward());
1596 // Similar to Redirect above, but the first URL is requested by POST,
1597 // the second URL is requested by GET. NavigationEntry::has_post_data_
1598 // must be cleared. http://crbug.com/21245
1599 TEST_F(NavigationControllerTest
, PostThenRedirect
) {
1600 NavigationControllerImpl
& controller
= controller_impl();
1601 TestNotificationTracker notifications
;
1602 RegisterForAllNavNotifications(¬ifications
, &controller
);
1604 const GURL
url1("http://foo1");
1605 const GURL
url2("http://foo2"); // Redirection target
1607 // First request as POST
1608 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1609 controller
.GetActiveEntry()->SetHasPostData(true);
1611 EXPECT_EQ(0U, notifications
.size());
1612 test_rvh()->SendNavigate(0, url2
);
1613 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1614 navigation_entry_committed_counter_
= 0;
1617 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1619 EXPECT_TRUE(controller
.GetPendingEntry());
1620 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1621 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
1623 ViewHostMsg_FrameNavigate_Params params
;
1626 params
.transition
= PAGE_TRANSITION_SERVER_REDIRECT
;
1627 params
.redirects
.push_back(GURL("http://foo1"));
1628 params
.redirects
.push_back(GURL("http://foo2"));
1629 params
.should_update_history
= false;
1630 params
.gesture
= NavigationGestureAuto
;
1631 params
.is_post
= false;
1632 params
.page_state
= PageState::CreateFromURL(url2
);
1634 LoadCommittedDetails details
;
1636 EXPECT_EQ(0U, notifications
.size());
1637 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1638 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1639 navigation_entry_committed_counter_
= 0;
1641 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_SAME_PAGE
);
1642 EXPECT_EQ(controller
.GetEntryCount(), 1);
1643 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1644 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1645 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1646 EXPECT_FALSE(controller
.GetPendingEntry());
1647 EXPECT_EQ(url2
, controller
.GetActiveEntry()->GetURL());
1648 EXPECT_FALSE(controller
.GetActiveEntry()->GetHasPostData());
1650 EXPECT_FALSE(controller
.CanGoBack());
1651 EXPECT_FALSE(controller
.CanGoForward());
1654 // A redirect right off the bat should be a NEW_PAGE.
1655 TEST_F(NavigationControllerTest
, ImmediateRedirect
) {
1656 NavigationControllerImpl
& controller
= controller_impl();
1657 TestNotificationTracker notifications
;
1658 RegisterForAllNavNotifications(¬ifications
, &controller
);
1660 const GURL
url1("http://foo1");
1661 const GURL
url2("http://foo2"); // Redirection target
1664 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1666 EXPECT_TRUE(controller
.GetPendingEntry());
1667 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1668 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
1670 ViewHostMsg_FrameNavigate_Params params
;
1673 params
.transition
= PAGE_TRANSITION_SERVER_REDIRECT
;
1674 params
.redirects
.push_back(GURL("http://foo1"));
1675 params
.redirects
.push_back(GURL("http://foo2"));
1676 params
.should_update_history
= false;
1677 params
.gesture
= NavigationGestureAuto
;
1678 params
.is_post
= false;
1679 params
.page_state
= PageState::CreateFromURL(url2
);
1681 LoadCommittedDetails details
;
1683 EXPECT_EQ(0U, notifications
.size());
1684 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1685 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1686 navigation_entry_committed_counter_
= 0;
1688 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_NEW_PAGE
);
1689 EXPECT_EQ(controller
.GetEntryCount(), 1);
1690 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1691 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1692 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1693 EXPECT_FALSE(controller
.GetPendingEntry());
1694 EXPECT_EQ(url2
, controller
.GetActiveEntry()->GetURL());
1696 EXPECT_FALSE(controller
.CanGoBack());
1697 EXPECT_FALSE(controller
.CanGoForward());
1700 // Tests navigation via link click within a subframe. A new navigation entry
1701 // should be created.
1702 TEST_F(NavigationControllerTest
, NewSubframe
) {
1703 NavigationControllerImpl
& controller
= controller_impl();
1704 TestNotificationTracker notifications
;
1705 RegisterForAllNavNotifications(¬ifications
, &controller
);
1707 const GURL
url1("http://foo1");
1708 test_rvh()->SendNavigate(0, url1
);
1709 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1710 navigation_entry_committed_counter_
= 0;
1712 const GURL
url2("http://foo2");
1713 ViewHostMsg_FrameNavigate_Params params
;
1716 params
.transition
= PAGE_TRANSITION_MANUAL_SUBFRAME
;
1717 params
.should_update_history
= false;
1718 params
.gesture
= NavigationGestureUser
;
1719 params
.is_post
= false;
1720 params
.page_state
= PageState::CreateFromURL(url2
);
1722 LoadCommittedDetails details
;
1723 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1724 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1725 navigation_entry_committed_counter_
= 0;
1726 EXPECT_EQ(url1
, details
.previous_url
);
1727 EXPECT_FALSE(details
.is_in_page
);
1728 EXPECT_FALSE(details
.is_main_frame
);
1730 // The new entry should be appended.
1731 EXPECT_EQ(2, controller
.GetEntryCount());
1733 // New entry should refer to the new page, but the old URL (entries only
1734 // reflect the toplevel URL).
1735 EXPECT_EQ(url1
, details
.entry
->GetURL());
1736 EXPECT_EQ(params
.page_id
, details
.entry
->GetPageID());
1739 // Some pages create a popup, then write an iframe into it. This causes a
1740 // subframe navigation without having any committed entry. Such navigations
1741 // just get thrown on the ground, but we shouldn't crash.
1742 TEST_F(NavigationControllerTest
, SubframeOnEmptyPage
) {
1743 NavigationControllerImpl
& controller
= controller_impl();
1744 TestNotificationTracker notifications
;
1745 RegisterForAllNavNotifications(¬ifications
, &controller
);
1747 // Navigation controller currently has no entries.
1748 const GURL
url("http://foo2");
1749 ViewHostMsg_FrameNavigate_Params params
;
1752 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
1753 params
.should_update_history
= false;
1754 params
.gesture
= NavigationGestureAuto
;
1755 params
.is_post
= false;
1756 params
.page_state
= PageState::CreateFromURL(url
);
1758 LoadCommittedDetails details
;
1759 EXPECT_FALSE(controller
.RendererDidNavigate(params
, &details
));
1760 EXPECT_EQ(0U, notifications
.size());
1763 // Auto subframes are ones the page loads automatically like ads. They should
1764 // not create new navigation entries.
1765 TEST_F(NavigationControllerTest
, AutoSubframe
) {
1766 NavigationControllerImpl
& controller
= controller_impl();
1767 TestNotificationTracker notifications
;
1768 RegisterForAllNavNotifications(¬ifications
, &controller
);
1770 const GURL
url1("http://foo1");
1771 test_rvh()->SendNavigate(0, url1
);
1772 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1773 navigation_entry_committed_counter_
= 0;
1775 const GURL
url2("http://foo2");
1776 ViewHostMsg_FrameNavigate_Params params
;
1779 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
1780 params
.should_update_history
= false;
1781 params
.gesture
= NavigationGestureUser
;
1782 params
.is_post
= false;
1783 params
.page_state
= PageState::CreateFromURL(url2
);
1785 // Navigating should do nothing.
1786 LoadCommittedDetails details
;
1787 EXPECT_FALSE(controller
.RendererDidNavigate(params
, &details
));
1788 EXPECT_EQ(0U, notifications
.size());
1790 // There should still be only one entry.
1791 EXPECT_EQ(1, controller
.GetEntryCount());
1794 // Tests navigation and then going back to a subframe navigation.
1795 TEST_F(NavigationControllerTest
, BackSubframe
) {
1796 NavigationControllerImpl
& controller
= controller_impl();
1797 TestNotificationTracker notifications
;
1798 RegisterForAllNavNotifications(¬ifications
, &controller
);
1801 const GURL
url1("http://foo1");
1802 test_rvh()->SendNavigate(0, url1
);
1803 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1804 navigation_entry_committed_counter_
= 0;
1806 // First manual subframe navigation.
1807 const GURL
url2("http://foo2");
1808 ViewHostMsg_FrameNavigate_Params params
;
1811 params
.transition
= PAGE_TRANSITION_MANUAL_SUBFRAME
;
1812 params
.should_update_history
= false;
1813 params
.gesture
= NavigationGestureUser
;
1814 params
.is_post
= false;
1815 params
.page_state
= PageState::CreateFromURL(url2
);
1817 // This should generate a new entry.
1818 LoadCommittedDetails details
;
1819 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1820 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1821 navigation_entry_committed_counter_
= 0;
1822 EXPECT_EQ(2, controller
.GetEntryCount());
1824 // Second manual subframe navigation should also make a new entry.
1825 const GURL
url3("http://foo3");
1828 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1829 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1830 navigation_entry_committed_counter_
= 0;
1831 EXPECT_EQ(3, controller
.GetEntryCount());
1832 EXPECT_EQ(2, controller
.GetCurrentEntryIndex());
1835 controller
.GoBack();
1838 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1839 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1840 navigation_entry_committed_counter_
= 0;
1841 EXPECT_EQ(3, controller
.GetEntryCount());
1842 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
1843 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1844 EXPECT_FALSE(controller
.GetPendingEntry());
1846 // Go back one more.
1847 controller
.GoBack();
1850 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1851 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1852 navigation_entry_committed_counter_
= 0;
1853 EXPECT_EQ(3, controller
.GetEntryCount());
1854 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
1855 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1856 EXPECT_FALSE(controller
.GetPendingEntry());
1859 TEST_F(NavigationControllerTest
, LinkClick
) {
1860 NavigationControllerImpl
& controller
= controller_impl();
1861 TestNotificationTracker notifications
;
1862 RegisterForAllNavNotifications(¬ifications
, &controller
);
1864 const GURL
url1("http://foo1");
1865 const GURL
url2("http://foo2");
1867 test_rvh()->SendNavigate(0, url1
);
1868 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1869 navigation_entry_committed_counter_
= 0;
1871 test_rvh()->SendNavigate(1, url2
);
1872 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1873 navigation_entry_committed_counter_
= 0;
1875 // Should not have produced a new session history entry.
1876 EXPECT_EQ(controller
.GetEntryCount(), 2);
1877 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1878 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1879 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1880 EXPECT_FALSE(controller
.GetPendingEntry());
1881 EXPECT_TRUE(controller
.CanGoBack());
1882 EXPECT_FALSE(controller
.CanGoForward());
1885 TEST_F(NavigationControllerTest
, InPage
) {
1886 NavigationControllerImpl
& controller
= controller_impl();
1887 TestNotificationTracker notifications
;
1888 RegisterForAllNavNotifications(¬ifications
, &controller
);
1891 const GURL
url1("http://foo");
1892 test_rvh()->SendNavigate(0, url1
);
1893 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1894 navigation_entry_committed_counter_
= 0;
1896 // Ensure main page navigation to same url respects the was_within_same_page
1897 // hint provided in the params.
1898 ViewHostMsg_FrameNavigate_Params self_params
;
1899 self_params
.page_id
= 0;
1900 self_params
.url
= url1
;
1901 self_params
.transition
= PAGE_TRANSITION_LINK
;
1902 self_params
.should_update_history
= false;
1903 self_params
.gesture
= NavigationGestureUser
;
1904 self_params
.is_post
= false;
1905 self_params
.page_state
= PageState::CreateFromURL(url1
);
1906 self_params
.was_within_same_page
= true;
1908 LoadCommittedDetails details
;
1909 EXPECT_TRUE(controller
.RendererDidNavigate(self_params
, &details
));
1910 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1911 navigation_entry_committed_counter_
= 0;
1912 EXPECT_TRUE(details
.is_in_page
);
1913 EXPECT_TRUE(details
.did_replace_entry
);
1914 EXPECT_EQ(1, controller
.GetEntryCount());
1916 // Fragment navigation to a new page_id.
1917 const GURL
url2("http://foo#a");
1918 ViewHostMsg_FrameNavigate_Params params
;
1921 params
.transition
= PAGE_TRANSITION_LINK
;
1922 params
.should_update_history
= false;
1923 params
.gesture
= NavigationGestureUser
;
1924 params
.is_post
= false;
1925 params
.page_state
= PageState::CreateFromURL(url2
);
1926 params
.was_within_same_page
= true;
1928 // This should generate a new entry.
1929 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1930 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1931 navigation_entry_committed_counter_
= 0;
1932 EXPECT_TRUE(details
.is_in_page
);
1933 EXPECT_FALSE(details
.did_replace_entry
);
1934 EXPECT_EQ(2, controller
.GetEntryCount());
1937 ViewHostMsg_FrameNavigate_Params
back_params(params
);
1938 controller
.GoBack();
1939 back_params
.url
= url1
;
1940 back_params
.page_id
= 0;
1941 EXPECT_TRUE(controller
.RendererDidNavigate(back_params
, &details
));
1942 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1943 navigation_entry_committed_counter_
= 0;
1944 EXPECT_TRUE(details
.is_in_page
);
1945 EXPECT_EQ(2, controller
.GetEntryCount());
1946 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
1947 EXPECT_EQ(back_params
.url
, controller
.GetActiveEntry()->GetURL());
1950 ViewHostMsg_FrameNavigate_Params
forward_params(params
);
1951 controller
.GoForward();
1952 forward_params
.url
= url2
;
1953 forward_params
.page_id
= 1;
1954 EXPECT_TRUE(controller
.RendererDidNavigate(forward_params
, &details
));
1955 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1956 navigation_entry_committed_counter_
= 0;
1957 EXPECT_TRUE(details
.is_in_page
);
1958 EXPECT_EQ(2, controller
.GetEntryCount());
1959 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
1960 EXPECT_EQ(forward_params
.url
,
1961 controller
.GetActiveEntry()->GetURL());
1963 // Now go back and forward again. This is to work around a bug where we would
1964 // compare the incoming URL with the last committed entry rather than the
1965 // one identified by an existing page ID. This would result in the second URL
1966 // losing the reference fragment when you navigate away from it and then back.
1967 controller
.GoBack();
1968 EXPECT_TRUE(controller
.RendererDidNavigate(back_params
, &details
));
1969 controller
.GoForward();
1970 EXPECT_TRUE(controller
.RendererDidNavigate(forward_params
, &details
));
1971 EXPECT_EQ(forward_params
.url
,
1972 controller
.GetActiveEntry()->GetURL());
1974 // Finally, navigate to an unrelated URL to make sure in_page is not sticky.
1975 const GURL
url3("http://bar");
1978 navigation_entry_committed_counter_
= 0;
1979 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1980 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1981 navigation_entry_committed_counter_
= 0;
1982 EXPECT_FALSE(details
.is_in_page
);
1983 EXPECT_EQ(3, controller
.GetEntryCount());
1984 EXPECT_EQ(2, controller
.GetCurrentEntryIndex());
1987 TEST_F(NavigationControllerTest
, InPage_Replace
) {
1988 NavigationControllerImpl
& controller
= controller_impl();
1989 TestNotificationTracker notifications
;
1990 RegisterForAllNavNotifications(¬ifications
, &controller
);
1993 const GURL
url1("http://foo");
1994 test_rvh()->SendNavigate(0, url1
);
1995 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
1996 navigation_entry_committed_counter_
= 0;
1998 // First navigation.
1999 const GURL
url2("http://foo#a");
2000 ViewHostMsg_FrameNavigate_Params params
;
2001 params
.page_id
= 0; // Same page_id
2003 params
.transition
= PAGE_TRANSITION_LINK
;
2004 params
.should_update_history
= false;
2005 params
.gesture
= NavigationGestureUser
;
2006 params
.is_post
= false;
2007 params
.page_state
= PageState::CreateFromURL(url2
);
2009 // This should NOT generate a new entry, nor prune the list.
2010 LoadCommittedDetails details
;
2011 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
2012 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2013 navigation_entry_committed_counter_
= 0;
2014 EXPECT_TRUE(details
.is_in_page
);
2015 EXPECT_TRUE(details
.did_replace_entry
);
2016 EXPECT_EQ(1, controller
.GetEntryCount());
2019 // Tests for http://crbug.com/40395
2022 // window.location.replace("#a");
2023 // window.location='http://foo3/';
2025 TEST_F(NavigationControllerTest
, ClientRedirectAfterInPageNavigation
) {
2026 NavigationControllerImpl
& controller
= controller_impl();
2027 TestNotificationTracker notifications
;
2028 RegisterForAllNavNotifications(¬ifications
, &controller
);
2030 // Load an initial page.
2032 const GURL
url("http://foo/");
2033 test_rvh()->SendNavigate(0, url
);
2034 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2035 navigation_entry_committed_counter_
= 0;
2038 // Navigate to a new page.
2040 const GURL
url("http://foo2/");
2041 test_rvh()->SendNavigate(1, url
);
2042 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2043 navigation_entry_committed_counter_
= 0;
2046 // Navigate within the page.
2048 const GURL
url("http://foo2/#a");
2049 ViewHostMsg_FrameNavigate_Params params
;
2050 params
.page_id
= 1; // Same page_id
2052 params
.transition
= PAGE_TRANSITION_LINK
;
2053 params
.redirects
.push_back(url
);
2054 params
.should_update_history
= true;
2055 params
.gesture
= NavigationGestureUnknown
;
2056 params
.is_post
= false;
2057 params
.page_state
= PageState::CreateFromURL(url
);
2059 // This should NOT generate a new entry, nor prune the list.
2060 LoadCommittedDetails details
;
2061 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
2062 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2063 navigation_entry_committed_counter_
= 0;
2064 EXPECT_TRUE(details
.is_in_page
);
2065 EXPECT_TRUE(details
.did_replace_entry
);
2066 EXPECT_EQ(2, controller
.GetEntryCount());
2069 // Perform a client redirect to a new page.
2071 const GURL
url("http://foo3/");
2072 ViewHostMsg_FrameNavigate_Params params
;
2073 params
.page_id
= 2; // New page_id
2075 params
.transition
= PAGE_TRANSITION_CLIENT_REDIRECT
;
2076 params
.redirects
.push_back(GURL("http://foo2/#a"));
2077 params
.redirects
.push_back(url
);
2078 params
.should_update_history
= true;
2079 params
.gesture
= NavigationGestureUnknown
;
2080 params
.is_post
= false;
2081 params
.page_state
= PageState::CreateFromURL(url
);
2083 // This SHOULD generate a new entry.
2084 LoadCommittedDetails details
;
2085 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
2086 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2087 navigation_entry_committed_counter_
= 0;
2088 EXPECT_FALSE(details
.is_in_page
);
2089 EXPECT_EQ(3, controller
.GetEntryCount());
2092 // Verify that BACK brings us back to http://foo2/.
2094 const GURL
url("http://foo2/");
2095 controller
.GoBack();
2096 test_rvh()->SendNavigate(1, url
);
2097 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
2098 navigation_entry_committed_counter_
= 0;
2099 EXPECT_EQ(url
, controller
.GetActiveEntry()->GetURL());
2103 // NotificationObserver implementation used in verifying we've received the
2104 // NOTIFICATION_NAV_LIST_PRUNED method.
2105 class PrunedListener
: public NotificationObserver
{
2107 explicit PrunedListener(NavigationControllerImpl
* controller
)
2108 : notification_count_(0) {
2109 registrar_
.Add(this, NOTIFICATION_NAV_LIST_PRUNED
,
2110 Source
<NavigationController
>(controller
));
2113 virtual void Observe(int type
,
2114 const NotificationSource
& source
,
2115 const NotificationDetails
& details
) OVERRIDE
{
2116 if (type
== NOTIFICATION_NAV_LIST_PRUNED
) {
2117 notification_count_
++;
2118 details_
= *(Details
<PrunedDetails
>(details
).ptr());
2122 // Number of times NAV_LIST_PRUNED has been observed.
2123 int notification_count_
;
2125 // Details from the last NAV_LIST_PRUNED.
2126 PrunedDetails details_
;
2129 NotificationRegistrar registrar_
;
2131 DISALLOW_COPY_AND_ASSIGN(PrunedListener
);
2134 // Tests that we limit the number of navigation entries created correctly.
2135 TEST_F(NavigationControllerTest
, EnforceMaxNavigationCount
) {
2136 NavigationControllerImpl
& controller
= controller_impl();
2137 size_t original_count
= NavigationControllerImpl::max_entry_count();
2138 const int kMaxEntryCount
= 5;
2140 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
2143 // Load up to the max count, all entries should be there.
2144 for (url_index
= 0; url_index
< kMaxEntryCount
; url_index
++) {
2145 GURL
url(base::StringPrintf("http://www.a.com/%d", url_index
));
2147 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2148 test_rvh()->SendNavigate(url_index
, url
);
2151 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
2153 // Created a PrunedListener to observe prune notifications.
2154 PrunedListener
listener(&controller
);
2156 // Navigate some more.
2157 GURL
url(base::StringPrintf("http://www.a.com/%d", url_index
));
2159 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2160 test_rvh()->SendNavigate(url_index
, url
);
2163 // We should have got a pruned navigation.
2164 EXPECT_EQ(1, listener
.notification_count_
);
2165 EXPECT_TRUE(listener
.details_
.from_front
);
2166 EXPECT_EQ(1, listener
.details_
.count
);
2168 // We expect http://www.a.com/0 to be gone.
2169 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
2170 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(),
2171 GURL("http:////www.a.com/1"));
2173 // More navigations.
2174 for (int i
= 0; i
< 3; i
++) {
2175 url
= GURL(base::StringPrintf("http:////www.a.com/%d", url_index
));
2177 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2178 test_rvh()->SendNavigate(url_index
, url
);
2181 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
2182 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(),
2183 GURL("http:////www.a.com/4"));
2185 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
2188 // Tests that we can do a restore and navigate to the restored entries and
2189 // everything is updated properly. This can be tricky since there is no
2190 // SiteInstance for the entries created initially.
2191 TEST_F(NavigationControllerTest
, RestoreNavigate
) {
2192 // Create a NavigationController with a restored set of tabs.
2193 GURL
url("http://foo");
2194 std::vector
<NavigationEntry
*> entries
;
2195 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
2196 url
, Referrer(), PAGE_TRANSITION_RELOAD
, false, std::string(),
2198 entry
->SetPageID(0);
2199 entry
->SetTitle(ASCIIToUTF16("Title"));
2200 entry
->SetPageState(PageState::CreateFromEncodedData("state"));
2201 const base::Time timestamp
= base::Time::Now();
2202 entry
->SetTimestamp(timestamp
);
2203 entries
.push_back(entry
);
2204 scoped_ptr
<WebContentsImpl
> our_contents(static_cast<WebContentsImpl
*>(
2205 WebContents::Create(WebContents::CreateParams(browser_context()))));
2206 NavigationControllerImpl
& our_controller
= our_contents
->GetController();
2207 our_controller
.Restore(
2209 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2211 ASSERT_EQ(0u, entries
.size());
2213 // Before navigating to the restored entry, it should have a restore_type
2214 // and no SiteInstance.
2215 ASSERT_EQ(1, our_controller
.GetEntryCount());
2216 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2217 NavigationEntryImpl::FromNavigationEntry(
2218 our_controller
.GetEntryAtIndex(0))->restore_type());
2219 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
2220 our_controller
.GetEntryAtIndex(0))->site_instance());
2222 // After navigating, we should have one entry, and it should be "pending".
2223 // It should now have a SiteInstance and no restore_type.
2224 our_controller
.GoToIndex(0);
2225 EXPECT_EQ(1, our_controller
.GetEntryCount());
2226 EXPECT_EQ(our_controller
.GetEntryAtIndex(0),
2227 our_controller
.GetPendingEntry());
2228 EXPECT_EQ(0, our_controller
.GetEntryAtIndex(0)->GetPageID());
2229 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2230 NavigationEntryImpl::FromNavigationEntry
2231 (our_controller
.GetEntryAtIndex(0))->restore_type());
2232 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
2233 our_controller
.GetEntryAtIndex(0))->site_instance());
2235 // Timestamp should remain the same before the navigation finishes.
2236 EXPECT_EQ(timestamp
, our_controller
.GetEntryAtIndex(0)->GetTimestamp());
2238 // Say we navigated to that entry.
2239 ViewHostMsg_FrameNavigate_Params params
;
2242 params
.transition
= PAGE_TRANSITION_LINK
;
2243 params
.should_update_history
= false;
2244 params
.gesture
= NavigationGestureUser
;
2245 params
.is_post
= false;
2246 params
.page_state
= PageState::CreateFromURL(url
);
2247 LoadCommittedDetails details
;
2248 our_controller
.RendererDidNavigate(params
, &details
);
2250 // There should be no longer any pending entry and one committed one. This
2251 // means that we were able to locate the entry, assign its site instance, and
2252 // commit it properly.
2253 EXPECT_EQ(1, our_controller
.GetEntryCount());
2254 EXPECT_EQ(0, our_controller
.GetLastCommittedEntryIndex());
2255 EXPECT_FALSE(our_controller
.GetPendingEntry());
2257 NavigationEntryImpl::FromNavigationEntry(
2258 our_controller
.GetLastCommittedEntry())->site_instance()->
2260 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2261 NavigationEntryImpl::FromNavigationEntry(
2262 our_controller
.GetEntryAtIndex(0))->restore_type());
2264 // Timestamp should have been updated.
2265 EXPECT_GE(our_controller
.GetEntryAtIndex(0)->GetTimestamp(), timestamp
);
2268 // Tests that we can still navigate to a restored entry after a different
2269 // navigation fails and clears the pending entry. http://crbug.com/90085
2270 TEST_F(NavigationControllerTest
, RestoreNavigateAfterFailure
) {
2271 // Create a NavigationController with a restored set of tabs.
2272 GURL
url("http://foo");
2273 std::vector
<NavigationEntry
*> entries
;
2274 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
2275 url
, Referrer(), PAGE_TRANSITION_RELOAD
, false, std::string(),
2277 entry
->SetPageID(0);
2278 entry
->SetTitle(ASCIIToUTF16("Title"));
2279 entry
->SetPageState(PageState::CreateFromEncodedData("state"));
2280 entries
.push_back(entry
);
2281 scoped_ptr
<WebContentsImpl
> our_contents(static_cast<WebContentsImpl
*>(
2282 WebContents::Create(WebContents::CreateParams(browser_context()))));
2283 NavigationControllerImpl
& our_controller
= our_contents
->GetController();
2284 our_controller
.Restore(
2285 0, NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
, &entries
);
2286 ASSERT_EQ(0u, entries
.size());
2288 // Before navigating to the restored entry, it should have a restore_type
2289 // and no SiteInstance.
2290 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2291 NavigationEntryImpl::FromNavigationEntry(
2292 our_controller
.GetEntryAtIndex(0))->restore_type());
2293 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
2294 our_controller
.GetEntryAtIndex(0))->site_instance());
2296 // After navigating, we should have one entry, and it should be "pending".
2297 // It should now have a SiteInstance and no restore_type.
2298 our_controller
.GoToIndex(0);
2299 EXPECT_EQ(1, our_controller
.GetEntryCount());
2300 EXPECT_EQ(our_controller
.GetEntryAtIndex(0),
2301 our_controller
.GetPendingEntry());
2302 EXPECT_EQ(0, our_controller
.GetEntryAtIndex(0)->GetPageID());
2303 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2304 NavigationEntryImpl::FromNavigationEntry(
2305 our_controller
.GetEntryAtIndex(0))->restore_type());
2306 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
2307 our_controller
.GetEntryAtIndex(0))->site_instance());
2309 // This pending navigation may have caused a different navigation to fail,
2310 // which causes the pending entry to be cleared.
2311 TestRenderViewHost
* rvh
=
2312 static_cast<TestRenderViewHost
*>(our_contents
->GetRenderViewHost());
2313 ViewHostMsg_DidFailProvisionalLoadWithError_Params fail_load_params
;
2314 fail_load_params
.frame_id
= 1;
2315 fail_load_params
.is_main_frame
= true;
2316 fail_load_params
.error_code
= net::ERR_ABORTED
;
2317 fail_load_params
.error_description
= string16();
2318 fail_load_params
.url
= url
;
2319 fail_load_params
.showing_repost_interstitial
= false;
2320 rvh
->OnMessageReceived(
2321 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
2324 // Now the pending restored entry commits.
2325 ViewHostMsg_FrameNavigate_Params params
;
2328 params
.transition
= PAGE_TRANSITION_LINK
;
2329 params
.should_update_history
= false;
2330 params
.gesture
= NavigationGestureUser
;
2331 params
.is_post
= false;
2332 params
.page_state
= PageState::CreateFromURL(url
);
2333 LoadCommittedDetails details
;
2334 our_controller
.RendererDidNavigate(params
, &details
);
2336 // There should be no pending entry and one committed one.
2337 EXPECT_EQ(1, our_controller
.GetEntryCount());
2338 EXPECT_EQ(0, our_controller
.GetLastCommittedEntryIndex());
2339 EXPECT_FALSE(our_controller
.GetPendingEntry());
2341 NavigationEntryImpl::FromNavigationEntry(
2342 our_controller
.GetLastCommittedEntry())->site_instance()->
2344 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2345 NavigationEntryImpl::FromNavigationEntry(
2346 our_controller
.GetEntryAtIndex(0))->restore_type());
2349 // Make sure that the page type and stuff is correct after an interstitial.
2350 TEST_F(NavigationControllerTest
, Interstitial
) {
2351 NavigationControllerImpl
& controller
= controller_impl();
2352 // First navigate somewhere normal.
2353 const GURL
url1("http://foo");
2355 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2356 test_rvh()->SendNavigate(0, url1
);
2358 // Now navigate somewhere with an interstitial.
2359 const GURL
url2("http://bar");
2361 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2362 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2363 set_page_type(PAGE_TYPE_INTERSTITIAL
);
2365 // At this point the interstitial will be displayed and the load will still
2366 // be pending. If the user continues, the load will commit.
2367 test_rvh()->SendNavigate(1, url2
);
2369 // The page should be a normal page again.
2370 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetURL());
2371 EXPECT_EQ(PAGE_TYPE_NORMAL
,
2372 controller
.GetLastCommittedEntry()->GetPageType());
2375 TEST_F(NavigationControllerTest
, RemoveEntry
) {
2376 NavigationControllerImpl
& controller
= controller_impl();
2377 const GURL
url1("http://foo/1");
2378 const GURL
url2("http://foo/2");
2379 const GURL
url3("http://foo/3");
2380 const GURL
url4("http://foo/4");
2381 const GURL
url5("http://foo/5");
2382 const GURL
pending_url("http://foo/pending");
2383 const GURL
default_url("http://foo/default");
2386 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2387 test_rvh()->SendNavigate(0, url1
);
2389 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2390 test_rvh()->SendNavigate(1, url2
);
2392 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2393 test_rvh()->SendNavigate(2, url3
);
2395 url4
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2396 test_rvh()->SendNavigate(3, url4
);
2398 url5
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2399 test_rvh()->SendNavigate(4, url5
);
2401 // Try to remove the last entry. Will fail because it is the current entry.
2402 EXPECT_FALSE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1));
2403 EXPECT_EQ(5, controller
.GetEntryCount());
2404 EXPECT_EQ(4, controller
.GetLastCommittedEntryIndex());
2406 // Go back, but don't commit yet. Check that we can't delete the current
2407 // and pending entries.
2408 controller
.GoBack();
2409 EXPECT_FALSE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1));
2410 EXPECT_FALSE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 2));
2412 // Now commit and delete the last entry.
2413 test_rvh()->SendNavigate(3, url4
);
2414 EXPECT_TRUE(controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1));
2415 EXPECT_EQ(4, controller
.GetEntryCount());
2416 EXPECT_EQ(3, controller
.GetLastCommittedEntryIndex());
2417 EXPECT_FALSE(controller
.GetPendingEntry());
2419 // Remove an entry which is not the last committed one.
2420 EXPECT_TRUE(controller
.RemoveEntryAtIndex(0));
2421 EXPECT_EQ(3, controller
.GetEntryCount());
2422 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
2423 EXPECT_FALSE(controller
.GetPendingEntry());
2425 // Remove the 2 remaining entries.
2426 controller
.RemoveEntryAtIndex(1);
2427 controller
.RemoveEntryAtIndex(0);
2429 // This should leave us with only the last committed entry.
2430 EXPECT_EQ(1, controller
.GetEntryCount());
2431 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
2434 // Tests the transient entry, making sure it goes away with all navigations.
2435 TEST_F(NavigationControllerTest
, TransientEntry
) {
2436 NavigationControllerImpl
& controller
= controller_impl();
2437 TestNotificationTracker notifications
;
2438 RegisterForAllNavNotifications(¬ifications
, &controller
);
2440 const GURL
url0("http://foo/0");
2441 const GURL
url1("http://foo/1");
2442 const GURL
url2("http://foo/2");
2443 const GURL
url3("http://foo/3");
2444 const GURL
url3_ref("http://foo/3#bar");
2445 const GURL
url4("http://foo/4");
2446 const GURL
transient_url("http://foo/transient");
2449 url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2450 test_rvh()->SendNavigate(0, url0
);
2452 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2453 test_rvh()->SendNavigate(1, url1
);
2455 notifications
.Reset();
2457 // Adding a transient with no pending entry.
2458 NavigationEntryImpl
* transient_entry
= new NavigationEntryImpl
;
2459 transient_entry
->SetURL(transient_url
);
2460 controller
.SetTransientEntry(transient_entry
);
2462 // We should not have received any notifications.
2463 EXPECT_EQ(0U, notifications
.size());
2466 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2467 EXPECT_EQ(controller
.GetEntryCount(), 3);
2468 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
2469 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
2470 EXPECT_TRUE(controller
.GetLastCommittedEntry());
2471 EXPECT_FALSE(controller
.GetPendingEntry());
2472 EXPECT_TRUE(controller
.CanGoBack());
2473 EXPECT_FALSE(controller
.CanGoForward());
2474 EXPECT_EQ(contents()->GetMaxPageID(), 1);
2478 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2479 test_rvh()->SendNavigate(2, url2
);
2481 // We should have navigated, transient entry should be gone.
2482 EXPECT_EQ(url2
, controller
.GetActiveEntry()->GetURL());
2483 EXPECT_EQ(controller
.GetEntryCount(), 3);
2485 // Add a transient again, then navigate with no pending entry this time.
2486 transient_entry
= new NavigationEntryImpl
;
2487 transient_entry
->SetURL(transient_url
);
2488 controller
.SetTransientEntry(transient_entry
);
2489 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2490 test_rvh()->SendNavigate(3, url3
);
2491 // Transient entry should be gone.
2492 EXPECT_EQ(url3
, controller
.GetActiveEntry()->GetURL());
2493 EXPECT_EQ(controller
.GetEntryCount(), 4);
2495 // Initiate a navigation, add a transient then commit navigation.
2497 url4
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2498 transient_entry
= new NavigationEntryImpl
;
2499 transient_entry
->SetURL(transient_url
);
2500 controller
.SetTransientEntry(transient_entry
);
2501 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2502 test_rvh()->SendNavigate(4, url4
);
2503 EXPECT_EQ(url4
, controller
.GetActiveEntry()->GetURL());
2504 EXPECT_EQ(controller
.GetEntryCount(), 5);
2506 // Add a transient and go back. This should simply remove the transient.
2507 transient_entry
= new NavigationEntryImpl
;
2508 transient_entry
->SetURL(transient_url
);
2509 controller
.SetTransientEntry(transient_entry
);
2510 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2511 EXPECT_TRUE(controller
.CanGoBack());
2512 EXPECT_FALSE(controller
.CanGoForward());
2513 controller
.GoBack();
2514 // Transient entry should be gone.
2515 EXPECT_EQ(url4
, controller
.GetActiveEntry()->GetURL());
2516 EXPECT_EQ(controller
.GetEntryCount(), 5);
2517 test_rvh()->SendNavigate(3, url3
);
2519 // Add a transient and go to an entry before the current one.
2520 transient_entry
= new NavigationEntryImpl
;
2521 transient_entry
->SetURL(transient_url
);
2522 controller
.SetTransientEntry(transient_entry
);
2523 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2524 controller
.GoToIndex(1);
2525 // The navigation should have been initiated, transient entry should be gone.
2526 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
2527 // Visible entry does not update for history navigations until commit.
2528 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2529 test_rvh()->SendNavigate(1, url1
);
2530 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2532 // Add a transient and go to an entry after the current one.
2533 transient_entry
= new NavigationEntryImpl
;
2534 transient_entry
->SetURL(transient_url
);
2535 controller
.SetTransientEntry(transient_entry
);
2536 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2537 controller
.GoToIndex(3);
2538 // The navigation should have been initiated, transient entry should be gone.
2539 // Because of the transient entry that is removed, going to index 3 makes us
2540 // land on url2 (which is visible after the commit).
2541 EXPECT_EQ(url2
, controller
.GetActiveEntry()->GetURL());
2542 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2543 test_rvh()->SendNavigate(2, url2
);
2544 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2546 // Add a transient and go forward.
2547 transient_entry
= new NavigationEntryImpl
;
2548 transient_entry
->SetURL(transient_url
);
2549 controller
.SetTransientEntry(transient_entry
);
2550 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2551 EXPECT_TRUE(controller
.CanGoForward());
2552 controller
.GoForward();
2553 // We should have navigated, transient entry should be gone.
2554 EXPECT_EQ(url3
, controller
.GetActiveEntry()->GetURL());
2555 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2556 test_rvh()->SendNavigate(3, url3
);
2557 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2559 // Add a transient and do an in-page navigation, replacing the current entry.
2560 transient_entry
= new NavigationEntryImpl
;
2561 transient_entry
->SetURL(transient_url
);
2562 controller
.SetTransientEntry(transient_entry
);
2563 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2564 test_rvh()->SendNavigate(3, url3_ref
);
2565 // Transient entry should be gone.
2566 EXPECT_EQ(url3_ref
, controller
.GetActiveEntry()->GetURL());
2568 // Ensure the URLs are correct.
2569 EXPECT_EQ(controller
.GetEntryCount(), 5);
2570 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2571 EXPECT_EQ(controller
.GetEntryAtIndex(1)->GetURL(), url1
);
2572 EXPECT_EQ(controller
.GetEntryAtIndex(2)->GetURL(), url2
);
2573 EXPECT_EQ(controller
.GetEntryAtIndex(3)->GetURL(), url3_ref
);
2574 EXPECT_EQ(controller
.GetEntryAtIndex(4)->GetURL(), url4
);
2577 // Test that Reload initiates a new navigation to a transient entry's URL.
2578 TEST_F(NavigationControllerTest
, ReloadTransient
) {
2579 NavigationControllerImpl
& controller
= controller_impl();
2580 const GURL
url0("http://foo/0");
2581 const GURL
url1("http://foo/1");
2582 const GURL
transient_url("http://foo/transient");
2584 // Load |url0|, and start a pending navigation to |url1|.
2586 url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2587 test_rvh()->SendNavigate(0, url0
);
2589 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2591 // A transient entry is added, interrupting the navigation.
2592 NavigationEntryImpl
* transient_entry
= new NavigationEntryImpl
;
2593 transient_entry
->SetURL(transient_url
);
2594 controller
.SetTransientEntry(transient_entry
);
2595 EXPECT_TRUE(controller
.GetTransientEntry());
2596 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2598 // The page is reloaded, which should remove the pending entry for |url1| and
2599 // the transient entry for |transient_url|, and start a navigation to
2601 controller
.Reload(true);
2602 EXPECT_FALSE(controller
.GetTransientEntry());
2603 EXPECT_TRUE(controller
.GetPendingEntry());
2604 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2605 ASSERT_EQ(controller
.GetEntryCount(), 1);
2606 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2608 // Load of |transient_url| completes.
2609 test_rvh()->SendNavigate(1, transient_url
);
2610 ASSERT_EQ(controller
.GetEntryCount(), 2);
2611 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2612 EXPECT_EQ(controller
.GetEntryAtIndex(1)->GetURL(), transient_url
);
2615 // Ensure that renderer initiated pending entries get replaced, so that we
2616 // don't show a stale virtual URL when a navigation commits.
2617 // See http://crbug.com/266922.
2618 TEST_F(NavigationControllerTest
, RendererInitiatedPendingEntries
) {
2619 NavigationControllerImpl
& controller
= controller_impl();
2621 const GURL
url1("nonexistent:12121");
2622 const GURL
url1_fixed("http://nonexistent:12121/");
2623 const GURL
url2("http://foo");
2625 // We create pending entries for renderer-initiated navigations so that we
2626 // can show them in new tabs when it is safe.
2627 contents()->DidStartProvisionalLoadForFrame(
2628 test_rvh(), 1, -1, true, url1
);
2630 // Simulate what happens if a BrowserURLHandler rewrites the URL, causing
2631 // the virtual URL to differ from the URL.
2632 controller
.GetPendingEntry()->SetURL(url1_fixed
);
2633 controller
.GetPendingEntry()->SetVirtualURL(url1
);
2635 EXPECT_EQ(url1_fixed
, controller
.GetPendingEntry()->GetURL());
2636 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetVirtualURL());
2638 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2639 is_renderer_initiated());
2641 // If the user clicks another link, we should replace the pending entry.
2642 contents()->DidStartProvisionalLoadForFrame(
2643 test_rvh(), 1, -1, true, url2
);
2644 EXPECT_EQ(url2
, controller
.GetPendingEntry()->GetURL());
2645 EXPECT_EQ(url2
, controller
.GetPendingEntry()->GetVirtualURL());
2647 // Once it commits, the URL and virtual URL should reflect the actual page.
2648 test_rvh()->SendNavigate(0, url2
);
2649 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetURL());
2650 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetVirtualURL());
2652 // We should not replace the pending entry for an error URL.
2653 contents()->DidStartProvisionalLoadForFrame(
2654 test_rvh(), 1, -1, true, url1
);
2655 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
2656 contents()->DidStartProvisionalLoadForFrame(
2657 test_rvh(), 1, -1, true, GURL(kUnreachableWebDataURL
));
2658 EXPECT_EQ(url1
, controller
.GetPendingEntry()->GetURL());
2661 // Tests that the URLs for renderer-initiated navigations are not displayed to
2662 // the user until the navigation commits, to prevent URL spoof attacks.
2663 // See http://crbug.com/99016.
2664 TEST_F(NavigationControllerTest
, DontShowRendererURLUntilCommit
) {
2665 NavigationControllerImpl
& controller
= controller_impl();
2666 TestNotificationTracker notifications
;
2667 RegisterForAllNavNotifications(¬ifications
, &controller
);
2669 const GURL
url0("http://foo/0");
2670 const GURL
url1("http://foo/1");
2672 // For typed navigations (browser-initiated), both active and visible entries
2673 // should update before commit.
2674 controller
.LoadURL(url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2675 EXPECT_EQ(url0
, controller
.GetActiveEntry()->GetURL());
2676 EXPECT_EQ(url0
, controller
.GetVisibleEntry()->GetURL());
2677 test_rvh()->SendNavigate(0, url0
);
2679 // For link clicks (renderer-initiated navigations), the active entry should
2680 // update before commit but the visible should not.
2681 NavigationController::LoadURLParams
load_url_params(url1
);
2682 load_url_params
.is_renderer_initiated
= true;
2683 controller
.LoadURLWithParams(load_url_params
);
2684 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
2685 EXPECT_EQ(url0
, controller
.GetVisibleEntry()->GetURL());
2687 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2688 is_renderer_initiated());
2690 // After commit, both should be updated, and we should no longer treat the
2691 // entry as renderer-initiated.
2692 test_rvh()->SendNavigate(1, url1
);
2693 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
2694 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2696 NavigationEntryImpl::FromNavigationEntry(
2697 controller
.GetLastCommittedEntry())->is_renderer_initiated());
2699 notifications
.Reset();
2702 // Tests that the URLs for renderer-initiated navigations in new tabs are
2703 // displayed to the user before commit, as long as the initial about:blank
2704 // page has not been modified. If so, we must revert to showing about:blank.
2705 // See http://crbug.com/9682.
2706 TEST_F(NavigationControllerTest
, ShowRendererURLInNewTabUntilModified
) {
2707 NavigationControllerImpl
& controller
= controller_impl();
2708 TestNotificationTracker notifications
;
2709 RegisterForAllNavNotifications(¬ifications
, &controller
);
2711 const GURL
url("http://foo");
2713 // For renderer-initiated navigations in new tabs (with no committed entries),
2714 // we show the pending entry's URL as long as the about:blank page is not
2716 NavigationController::LoadURLParams
load_url_params(url
);
2717 load_url_params
.transition_type
= PAGE_TRANSITION_LINK
;
2718 load_url_params
.is_renderer_initiated
= true;
2719 controller
.LoadURLWithParams(load_url_params
);
2720 EXPECT_EQ(url
, controller
.GetActiveEntry()->GetURL());
2721 EXPECT_EQ(url
, controller
.GetVisibleEntry()->GetURL());
2723 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2724 is_renderer_initiated());
2725 EXPECT_TRUE(controller
.IsInitialNavigation());
2726 EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
2728 // There should be no title yet.
2729 EXPECT_TRUE(contents()->GetTitle().empty());
2731 // If something else modifies the contents of the about:blank page, then
2732 // we must revert to showing about:blank to avoid a URL spoof.
2733 test_rvh()->OnMessageReceived(
2734 ViewHostMsg_DidAccessInitialDocument(0));
2735 EXPECT_TRUE(test_rvh()->has_accessed_initial_document());
2736 EXPECT_FALSE(controller
.GetVisibleEntry());
2737 EXPECT_EQ(url
, controller
.GetActiveEntry()->GetURL());
2739 notifications
.Reset();
2742 TEST_F(NavigationControllerTest
, DontShowRendererURLInNewTabAfterCommit
) {
2743 NavigationControllerImpl
& controller
= controller_impl();
2744 TestNotificationTracker notifications
;
2745 RegisterForAllNavNotifications(¬ifications
, &controller
);
2747 const GURL
url1("http://foo/eh");
2748 const GURL
url2("http://foo/bee");
2750 // For renderer-initiated navigations in new tabs (with no committed entries),
2751 // we show the pending entry's URL as long as the about:blank page is not
2753 NavigationController::LoadURLParams
load_url_params(url1
);
2754 load_url_params
.transition_type
= PAGE_TRANSITION_LINK
;
2755 load_url_params
.is_renderer_initiated
= true;
2756 controller
.LoadURLWithParams(load_url_params
);
2757 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
2758 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2760 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2761 is_renderer_initiated());
2762 EXPECT_TRUE(controller
.IsInitialNavigation());
2763 EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
2765 // Simulate a commit and then starting a new pending navigation.
2766 test_rvh()->SendNavigate(0, url1
);
2767 NavigationController::LoadURLParams
load_url2_params(url2
);
2768 load_url2_params
.transition_type
= PAGE_TRANSITION_LINK
;
2769 load_url2_params
.is_renderer_initiated
= true;
2770 controller
.LoadURLWithParams(load_url2_params
);
2772 // We should not consider this an initial navigation, and thus should
2773 // not show the pending URL.
2774 EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
2775 EXPECT_FALSE(controller
.IsInitialNavigation());
2776 EXPECT_TRUE(controller
.GetVisibleEntry());
2777 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2779 notifications
.Reset();
2782 // Tests that IsInPageNavigation returns appropriate results. Prevents
2783 // regression for bug 1126349.
2784 TEST_F(NavigationControllerTest
, IsInPageNavigation
) {
2785 NavigationControllerImpl
& controller
= controller_impl();
2786 // Navigate to URL with no refs.
2787 const GURL
url("http://www.google.com/home.html");
2788 test_rvh()->SendNavigate(0, url
);
2790 // Reloading the page is not an in-page navigation.
2791 EXPECT_FALSE(controller
.IsURLInPageNavigation(url
));
2792 const GURL
other_url("http://www.google.com/add.html");
2793 EXPECT_FALSE(controller
.IsURLInPageNavigation(other_url
));
2794 const GURL
url_with_ref("http://www.google.com/home.html#my_ref");
2795 EXPECT_TRUE(controller
.IsURLInPageNavigation(url_with_ref
));
2797 // Navigate to URL with refs.
2798 test_rvh()->SendNavigate(1, url_with_ref
);
2800 // Reloading the page is not an in-page navigation.
2801 EXPECT_FALSE(controller
.IsURLInPageNavigation(url_with_ref
));
2802 EXPECT_FALSE(controller
.IsURLInPageNavigation(url
));
2803 EXPECT_FALSE(controller
.IsURLInPageNavigation(other_url
));
2804 const GURL
other_url_with_ref("http://www.google.com/home.html#my_other_ref");
2805 EXPECT_TRUE(controller
.IsURLInPageNavigation(other_url_with_ref
));
2807 // Going to the same url again will be considered in-page
2808 // if the renderer says it is even if the navigation type isn't IN_PAGE.
2809 EXPECT_TRUE(controller
.IsURLInPageNavigation(url_with_ref
, true,
2810 NAVIGATION_TYPE_UNKNOWN
));
2812 // Going back to the non ref url will be considered in-page if the navigation
2814 EXPECT_TRUE(controller
.IsURLInPageNavigation(url
, true,
2815 NAVIGATION_TYPE_IN_PAGE
));
2818 // Some pages can have subframes with the same base URL (minus the reference) as
2819 // the main page. Even though this is hard, it can happen, and we don't want
2820 // these subframe navigations to affect the toplevel document. They should
2821 // instead be ignored. http://crbug.com/5585
2822 TEST_F(NavigationControllerTest
, SameSubframe
) {
2823 NavigationControllerImpl
& controller
= controller_impl();
2824 // Navigate the main frame.
2825 const GURL
url("http://www.google.com/");
2826 test_rvh()->SendNavigate(0, url
);
2828 // We should be at the first navigation entry.
2829 EXPECT_EQ(controller
.GetEntryCount(), 1);
2830 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
2832 // Navigate a subframe that would normally count as in-page.
2833 const GURL
subframe("http://www.google.com/#");
2834 ViewHostMsg_FrameNavigate_Params params
;
2836 params
.url
= subframe
;
2837 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
2838 params
.should_update_history
= false;
2839 params
.gesture
= NavigationGestureAuto
;
2840 params
.is_post
= false;
2841 params
.page_state
= PageState::CreateFromURL(subframe
);
2842 LoadCommittedDetails details
;
2843 EXPECT_FALSE(controller
.RendererDidNavigate(params
, &details
));
2845 // Nothing should have changed.
2846 EXPECT_EQ(controller
.GetEntryCount(), 1);
2847 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
2850 // Make sure that on cloning a WebContentsImpl and going back needs_reload is
2852 TEST_F(NavigationControllerTest
, CloneAndGoBack
) {
2853 NavigationControllerImpl
& controller
= controller_impl();
2854 const GURL
url1("http://foo1");
2855 const GURL
url2("http://foo2");
2856 const string16
title(ASCIIToUTF16("Title"));
2858 NavigateAndCommit(url1
);
2859 controller
.GetActiveEntry()->SetTitle(title
);
2860 NavigateAndCommit(url2
);
2862 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
2864 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
2865 EXPECT_TRUE(clone
->GetController().NeedsReload());
2866 clone
->GetController().GoBack();
2867 // Navigating back should have triggered needs_reload_ to go false.
2868 EXPECT_FALSE(clone
->GetController().NeedsReload());
2870 // Ensure that the pending URL and its title are visible.
2871 EXPECT_EQ(url1
, clone
->GetController().GetVisibleEntry()->GetURL());
2872 EXPECT_EQ(title
, clone
->GetTitle());
2875 // Make sure that reloading a cloned tab doesn't change its pending entry index.
2876 // See http://crbug.com/234491.
2877 TEST_F(NavigationControllerTest
, CloneAndReload
) {
2878 NavigationControllerImpl
& controller
= controller_impl();
2879 const GURL
url1("http://foo1");
2880 const GURL
url2("http://foo2");
2881 const string16
title(ASCIIToUTF16("Title"));
2883 NavigateAndCommit(url1
);
2884 controller
.GetActiveEntry()->SetTitle(title
);
2885 NavigateAndCommit(url2
);
2887 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
2888 clone
->GetController().LoadIfNecessary();
2890 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
2891 EXPECT_EQ(1, clone
->GetController().GetPendingEntryIndex());
2893 clone
->GetController().Reload(true);
2894 EXPECT_EQ(1, clone
->GetController().GetPendingEntryIndex());
2897 // Make sure that cloning a WebContentsImpl doesn't copy interstitials.
2898 TEST_F(NavigationControllerTest
, CloneOmitsInterstitials
) {
2899 NavigationControllerImpl
& controller
= controller_impl();
2900 const GURL
url1("http://foo1");
2901 const GURL
url2("http://foo2");
2903 NavigateAndCommit(url1
);
2904 NavigateAndCommit(url2
);
2906 // Add an interstitial entry. Should be deleted with controller.
2907 NavigationEntryImpl
* interstitial_entry
= new NavigationEntryImpl();
2908 interstitial_entry
->set_page_type(PAGE_TYPE_INTERSTITIAL
);
2909 controller
.SetTransientEntry(interstitial_entry
);
2911 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
2913 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
2916 // Tests a subframe navigation while a toplevel navigation is pending.
2917 // http://crbug.com/43967
2918 TEST_F(NavigationControllerTest
, SubframeWhilePending
) {
2919 NavigationControllerImpl
& controller
= controller_impl();
2920 // Load the first page.
2921 const GURL
url1("http://foo/");
2922 NavigateAndCommit(url1
);
2924 // Now start a pending load to a totally different page, but don't commit it.
2925 const GURL
url2("http://bar/");
2927 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2929 // Send a subframe update from the first page, as if one had just
2930 // automatically loaded. Auto subframes don't increment the page ID.
2931 const GURL
url1_sub("http://foo/subframe");
2932 ViewHostMsg_FrameNavigate_Params params
;
2933 params
.page_id
= controller
.GetLastCommittedEntry()->GetPageID();
2934 params
.url
= url1_sub
;
2935 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
2936 params
.should_update_history
= false;
2937 params
.gesture
= NavigationGestureAuto
;
2938 params
.is_post
= false;
2939 params
.page_state
= PageState::CreateFromURL(url1_sub
);
2940 LoadCommittedDetails details
;
2942 // This should return false meaning that nothing was actually updated.
2943 EXPECT_FALSE(controller
.RendererDidNavigate(params
, &details
));
2945 // The notification should have updated the last committed one, and not
2946 // the pending load.
2947 EXPECT_EQ(url1
, controller
.GetLastCommittedEntry()->GetURL());
2949 // The active entry should be unchanged by the subframe load.
2950 EXPECT_EQ(url2
, controller
.GetActiveEntry()->GetURL());
2953 // Test CopyStateFrom with 2 urls, the first selected and nothing in the target.
2954 TEST_F(NavigationControllerTest
, CopyStateFrom
) {
2955 NavigationControllerImpl
& controller
= controller_impl();
2956 const GURL
url1("http://foo1");
2957 const GURL
url2("http://foo2");
2959 NavigateAndCommit(url1
);
2960 NavigateAndCommit(url2
);
2961 controller
.GoBack();
2962 contents()->CommitPendingNavigation();
2964 scoped_ptr
<TestWebContents
> other_contents(
2965 static_cast<TestWebContents
*>(CreateTestWebContents()));
2966 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2967 other_controller
.CopyStateFrom(controller
);
2969 // other_controller should now contain 2 urls.
2970 ASSERT_EQ(2, other_controller
.GetEntryCount());
2971 // We should be looking at the first one.
2972 ASSERT_EQ(0, other_controller
.GetCurrentEntryIndex());
2974 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2975 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
2976 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
2977 // This is a different site than url1, so the IDs start again at 0.
2978 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(1)->GetPageID());
2980 // The max page ID map should be copied over and updated with the max page ID
2981 // from the current tab.
2982 SiteInstance
* instance1
=
2983 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0));
2984 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
2986 // Ensure the SessionStorageNamespaceMaps are the same size and have
2987 // the same partitons loaded.
2989 // TODO(ajwong): We should load a url from a different partition earlier
2990 // to make sure this map has more than one entry.
2991 const SessionStorageNamespaceMap
& session_storage_namespace_map
=
2992 controller
.GetSessionStorageNamespaceMap();
2993 const SessionStorageNamespaceMap
& other_session_storage_namespace_map
=
2994 other_controller
.GetSessionStorageNamespaceMap();
2995 EXPECT_EQ(session_storage_namespace_map
.size(),
2996 other_session_storage_namespace_map
.size());
2997 for (SessionStorageNamespaceMap::const_iterator it
=
2998 session_storage_namespace_map
.begin();
2999 it
!= session_storage_namespace_map
.end();
3001 SessionStorageNamespaceMap::const_iterator other
=
3002 other_session_storage_namespace_map
.find(it
->first
);
3003 EXPECT_TRUE(other
!= other_session_storage_namespace_map
.end());
3007 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
3008 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune
) {
3009 NavigationControllerImpl
& controller
= controller_impl();
3010 const GURL
url1("http://foo/1");
3011 const GURL
url2("http://foo/2");
3012 const GURL
url3("http://foo/3");
3014 NavigateAndCommit(url1
);
3015 NavigateAndCommit(url2
);
3017 // First two entries should have the same SiteInstance.
3018 SiteInstance
* instance1
=
3019 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(0));
3020 SiteInstance
* instance2
=
3021 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(1));
3022 EXPECT_EQ(instance1
, instance2
);
3023 EXPECT_EQ(0, controller
.GetEntryAtIndex(0)->GetPageID());
3024 EXPECT_EQ(1, controller
.GetEntryAtIndex(1)->GetPageID());
3025 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1
));
3027 scoped_ptr
<TestWebContents
> other_contents(
3028 static_cast<TestWebContents
*>(CreateTestWebContents()));
3029 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3030 other_contents
->NavigateAndCommit(url3
);
3031 other_contents
->ExpectSetHistoryLengthAndPrune(
3032 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3033 other_controller
.GetEntryAtIndex(0)->GetPageID());
3034 other_controller
.CopyStateFromAndPrune(&controller
);
3036 // other_controller should now contain the 3 urls: url1, url2 and url3.
3038 ASSERT_EQ(3, other_controller
.GetEntryCount());
3040 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3042 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3043 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3044 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
3045 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
3046 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(1)->GetPageID());
3047 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3049 // A new SiteInstance should be used for the new tab.
3050 SiteInstance
* instance3
=
3051 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
3052 EXPECT_NE(instance3
, instance1
);
3054 // The max page ID map should be copied over and updated with the max page ID
3055 // from the current tab.
3056 EXPECT_EQ(1, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3057 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance3
));
3060 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry in
3062 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune2
) {
3063 NavigationControllerImpl
& controller
= controller_impl();
3064 const GURL
url1("http://foo1");
3065 const GURL
url2("http://foo2");
3066 const GURL
url3("http://foo3");
3068 NavigateAndCommit(url1
);
3069 NavigateAndCommit(url2
);
3070 controller
.GoBack();
3071 contents()->CommitPendingNavigation();
3073 scoped_ptr
<TestWebContents
> other_contents(
3074 static_cast<TestWebContents
*>(CreateTestWebContents()));
3075 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3076 other_contents
->NavigateAndCommit(url3
);
3077 other_contents
->ExpectSetHistoryLengthAndPrune(
3078 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 1,
3079 other_controller
.GetEntryAtIndex(0)->GetPageID());
3080 other_controller
.CopyStateFromAndPrune(&controller
);
3082 // other_controller should now contain: url1, url3
3084 ASSERT_EQ(2, other_controller
.GetEntryCount());
3085 ASSERT_EQ(1, other_controller
.GetCurrentEntryIndex());
3087 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3088 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3089 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(1)->GetPageID());
3091 // The max page ID map should be copied over and updated with the max page ID
3092 // from the current tab.
3093 SiteInstance
* instance1
=
3094 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(1));
3095 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3098 // Test CopyStateFromAndPrune with 2 urls, the last selected and 2 entries in
3100 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune3
) {
3101 NavigationControllerImpl
& controller
= controller_impl();
3102 const GURL
url1("http://foo1");
3103 const GURL
url2("http://foo2");
3104 const GURL
url3("http://foo3");
3105 const GURL
url4("http://foo4");
3107 NavigateAndCommit(url1
);
3108 NavigateAndCommit(url2
);
3110 scoped_ptr
<TestWebContents
> other_contents(
3111 static_cast<TestWebContents
*>(CreateTestWebContents()));
3112 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3113 other_contents
->NavigateAndCommit(url3
);
3114 other_contents
->NavigateAndCommit(url4
);
3115 other_contents
->ExpectSetHistoryLengthAndPrune(
3116 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(1)), 2,
3117 other_controller
.GetEntryAtIndex(0)->GetPageID());
3118 other_controller
.CopyStateFromAndPrune(&controller
);
3120 // other_controller should now contain: url1, url2, url4
3122 ASSERT_EQ(3, other_controller
.GetEntryCount());
3123 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3125 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3126 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3127 EXPECT_EQ(url4
, other_controller
.GetEntryAtIndex(2)->GetURL());
3129 // The max page ID map should be copied over and updated with the max page ID
3130 // from the current tab.
3131 SiteInstance
* instance1
=
3132 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
3133 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3136 // Test CopyStateFromAndPrune with 2 urls, 2 entries in the target, with
3137 // not the last entry selected in the target.
3138 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneNotLast
) {
3139 NavigationControllerImpl
& controller
= controller_impl();
3140 const GURL
url1("http://foo1");
3141 const GURL
url2("http://foo2");
3142 const GURL
url3("http://foo3");
3143 const GURL
url4("http://foo4");
3145 NavigateAndCommit(url1
);
3146 NavigateAndCommit(url2
);
3148 scoped_ptr
<TestWebContents
> other_contents(
3149 static_cast<TestWebContents
*>(CreateTestWebContents()));
3150 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3151 other_contents
->NavigateAndCommit(url3
);
3152 other_contents
->NavigateAndCommit(url4
);
3153 other_controller
.GoBack();
3154 other_contents
->CommitPendingNavigation();
3155 other_contents
->ExpectSetHistoryLengthAndPrune(
3156 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3157 other_controller
.GetEntryAtIndex(0)->GetPageID());
3158 other_controller
.CopyStateFromAndPrune(&controller
);
3160 // other_controller should now contain: url1, url2, url3
3162 ASSERT_EQ(3, other_controller
.GetEntryCount());
3163 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3165 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3166 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3167 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
3169 // The max page ID map should be copied over and updated with the max page ID
3170 // from the current tab.
3171 SiteInstance
* instance1
=
3172 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
3173 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3176 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry plus
3177 // a pending entry in the target.
3178 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneTargetPending
) {
3179 NavigationControllerImpl
& controller
= controller_impl();
3180 const GURL
url1("http://foo1");
3181 const GURL
url2("http://foo2");
3182 const GURL
url3("http://foo3");
3183 const GURL
url4("http://foo4");
3185 NavigateAndCommit(url1
);
3186 NavigateAndCommit(url2
);
3187 controller
.GoBack();
3188 contents()->CommitPendingNavigation();
3190 scoped_ptr
<TestWebContents
> other_contents(
3191 static_cast<TestWebContents
*>(CreateTestWebContents()));
3192 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3193 other_contents
->NavigateAndCommit(url3
);
3194 other_controller
.LoadURL(
3195 url4
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
3196 other_contents
->ExpectSetHistoryLengthAndPrune(
3197 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 1,
3198 other_controller
.GetEntryAtIndex(0)->GetPageID());
3199 other_controller
.CopyStateFromAndPrune(&controller
);
3201 // other_controller should now contain url1, url3, and a pending entry
3204 ASSERT_EQ(2, other_controller
.GetEntryCount());
3205 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
3207 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3208 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3210 // And there should be a pending entry for url4.
3211 ASSERT_TRUE(other_controller
.GetPendingEntry());
3212 EXPECT_EQ(url4
, other_controller
.GetPendingEntry()->GetURL());
3214 // The max page ID map should be copied over and updated with the max page ID
3215 // from the current tab.
3216 SiteInstance
* instance1
=
3217 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0));
3218 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3221 // Test CopyStateFromAndPrune with 1 url in the source, 1 entry and a pending
3222 // client redirect entry (with the same page ID) in the target. This used to
3223 // crash because the last committed entry would be pruned but max_page_id
3224 // remembered the page ID (http://crbug.com/234809).
3225 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneTargetPending2
) {
3226 NavigationControllerImpl
& controller
= controller_impl();
3227 const GURL
url1("http://foo1");
3228 const GURL
url2a("http://foo2/a");
3229 const GURL
url2b("http://foo2/b");
3231 NavigateAndCommit(url1
);
3233 scoped_ptr
<TestWebContents
> other_contents(
3234 static_cast<TestWebContents
*>(CreateTestWebContents()));
3235 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3236 other_contents
->NavigateAndCommit(url2a
);
3237 // Simulate a client redirect, which has the same page ID as entry 2a.
3238 other_controller
.LoadURL(
3239 url2b
, Referrer(), PAGE_TRANSITION_LINK
, std::string());
3240 other_controller
.GetPendingEntry()->SetPageID(
3241 other_controller
.GetLastCommittedEntry()->GetPageID());
3243 other_contents
->ExpectSetHistoryLengthAndPrune(
3244 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 1,
3245 other_controller
.GetEntryAtIndex(0)->GetPageID());
3246 other_controller
.CopyStateFromAndPrune(&controller
);
3248 // other_controller should now contain url1, url2a, and a pending entry
3251 ASSERT_EQ(2, other_controller
.GetEntryCount());
3252 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
3254 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3255 EXPECT_EQ(url2a
, other_controller
.GetEntryAtIndex(1)->GetURL());
3257 // And there should be a pending entry for url4.
3258 ASSERT_TRUE(other_controller
.GetPendingEntry());
3259 EXPECT_EQ(url2b
, other_controller
.GetPendingEntry()->GetURL());
3261 // Let the pending entry commit.
3262 other_contents
->CommitPendingNavigation();
3264 // The max page ID map should be copied over and updated with the max page ID
3265 // from the current tab.
3266 SiteInstance
* instance1
=
3267 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(1));
3268 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3271 // Test CopyStateFromAndPrune with 2 urls, a back navigation pending in the
3272 // source, and 1 entry in the target. The back pending entry should be ignored.
3273 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneSourcePending
) {
3274 NavigationControllerImpl
& controller
= controller_impl();
3275 const GURL
url1("http://foo1");
3276 const GURL
url2("http://foo2");
3277 const GURL
url3("http://foo3");
3279 NavigateAndCommit(url1
);
3280 NavigateAndCommit(url2
);
3281 controller
.GoBack();
3283 scoped_ptr
<TestWebContents
> other_contents(
3284 static_cast<TestWebContents
*>(CreateTestWebContents()));
3285 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3286 other_contents
->NavigateAndCommit(url3
);
3287 other_contents
->ExpectSetHistoryLengthAndPrune(
3288 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3289 other_controller
.GetEntryAtIndex(0)->GetPageID());
3290 other_controller
.CopyStateFromAndPrune(&controller
);
3292 // other_controller should now contain: url1, url2, url3
3294 ASSERT_EQ(3, other_controller
.GetEntryCount());
3295 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3297 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
3298 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
3299 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
3300 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3302 // The max page ID map should be copied over and updated with the max page ID
3303 // from the current tab.
3304 SiteInstance
* instance1
=
3305 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
3306 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
3309 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest,
3310 // when the max entry count is 3. We should prune one entry.
3311 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneMaxEntries
) {
3312 NavigationControllerImpl
& controller
= controller_impl();
3313 size_t original_count
= NavigationControllerImpl::max_entry_count();
3314 const int kMaxEntryCount
= 3;
3316 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
3318 const GURL
url1("http://foo/1");
3319 const GURL
url2("http://foo/2");
3320 const GURL
url3("http://foo/3");
3321 const GURL
url4("http://foo/4");
3323 // Create a PrunedListener to observe prune notifications.
3324 PrunedListener
listener(&controller
);
3326 NavigateAndCommit(url1
);
3327 NavigateAndCommit(url2
);
3328 NavigateAndCommit(url3
);
3330 scoped_ptr
<TestWebContents
> other_contents(
3331 static_cast<TestWebContents
*>(CreateTestWebContents()));
3332 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
3333 other_contents
->NavigateAndCommit(url4
);
3334 other_contents
->ExpectSetHistoryLengthAndPrune(
3335 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
3336 other_controller
.GetEntryAtIndex(0)->GetPageID());
3337 other_controller
.CopyStateFromAndPrune(&controller
);
3339 // We should have received a pruned notification.
3340 EXPECT_EQ(1, listener
.notification_count_
);
3341 EXPECT_TRUE(listener
.details_
.from_front
);
3342 EXPECT_EQ(1, listener
.details_
.count
);
3344 // other_controller should now contain only 3 urls: url2, url3 and url4.
3346 ASSERT_EQ(3, other_controller
.GetEntryCount());
3348 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
3350 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(0)->GetURL());
3351 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
3352 EXPECT_EQ(url4
, other_controller
.GetEntryAtIndex(2)->GetURL());
3353 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(0)->GetPageID());
3354 EXPECT_EQ(2, other_controller
.GetEntryAtIndex(1)->GetPageID());
3355 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
3357 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
3360 // Tests that navigations initiated from the page (with the history object)
3361 // work as expected without navigation entries.
3362 TEST_F(NavigationControllerTest
, HistoryNavigate
) {
3363 NavigationControllerImpl
& controller
= controller_impl();
3364 const GURL
url1("http://foo/1");
3365 const GURL
url2("http://foo/2");
3366 const GURL
url3("http://foo/3");
3368 NavigateAndCommit(url1
);
3369 NavigateAndCommit(url2
);
3370 NavigateAndCommit(url3
);
3371 controller
.GoBack();
3372 contents()->CommitPendingNavigation();
3374 // Simulate the page calling history.back(), it should not create a pending
3376 contents()->OnGoToEntryAtOffset(-1);
3377 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3378 // The actual cross-navigation is suspended until the current RVH tells us
3379 // it unloaded, simulate that.
3380 contents()->ProceedWithCrossSiteNavigation();
3381 // Also make sure we told the page to navigate.
3382 const IPC::Message
* message
=
3383 process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID
);
3384 ASSERT_TRUE(message
!= NULL
);
3385 Tuple1
<ViewMsg_Navigate_Params
> nav_params
;
3386 ViewMsg_Navigate::Read(message
, &nav_params
);
3387 EXPECT_EQ(url1
, nav_params
.a
.url
);
3388 process()->sink().ClearMessages();
3390 // Now test history.forward()
3391 contents()->OnGoToEntryAtOffset(1);
3392 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3393 // The actual cross-navigation is suspended until the current RVH tells us
3394 // it unloaded, simulate that.
3395 contents()->ProceedWithCrossSiteNavigation();
3396 message
= process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID
);
3397 ASSERT_TRUE(message
!= NULL
);
3398 ViewMsg_Navigate::Read(message
, &nav_params
);
3399 EXPECT_EQ(url3
, nav_params
.a
.url
);
3400 process()->sink().ClearMessages();
3402 // Make sure an extravagant history.go() doesn't break.
3403 contents()->OnGoToEntryAtOffset(120); // Out of bounds.
3404 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3405 message
= process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID
);
3406 EXPECT_TRUE(message
== NULL
);
3409 // Test call to PruneAllButVisible for the only entry.
3410 TEST_F(NavigationControllerTest
, PruneAllButVisibleForSingle
) {
3411 NavigationControllerImpl
& controller
= controller_impl();
3412 const GURL
url1("http://foo1");
3413 NavigateAndCommit(url1
);
3415 contents()->ExpectSetHistoryLengthAndPrune(
3416 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(0)), 0,
3417 controller
.GetEntryAtIndex(0)->GetPageID());
3419 controller
.PruneAllButVisible();
3421 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3422 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url1
);
3425 // Test call to PruneAllButVisible for first entry.
3426 TEST_F(NavigationControllerTest
, PruneAllButVisibleForFirst
) {
3427 NavigationControllerImpl
& controller
= controller_impl();
3428 const GURL
url1("http://foo/1");
3429 const GURL
url2("http://foo/2");
3430 const GURL
url3("http://foo/3");
3432 NavigateAndCommit(url1
);
3433 NavigateAndCommit(url2
);
3434 NavigateAndCommit(url3
);
3435 controller
.GoBack();
3436 controller
.GoBack();
3437 contents()->CommitPendingNavigation();
3439 contents()->ExpectSetHistoryLengthAndPrune(
3440 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(0)), 0,
3441 controller
.GetEntryAtIndex(0)->GetPageID());
3443 controller
.PruneAllButVisible();
3445 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3446 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url1
);
3449 // Test call to PruneAllButVisible for intermediate entry.
3450 TEST_F(NavigationControllerTest
, PruneAllButVisibleForIntermediate
) {
3451 NavigationControllerImpl
& controller
= controller_impl();
3452 const GURL
url1("http://foo/1");
3453 const GURL
url2("http://foo/2");
3454 const GURL
url3("http://foo/3");
3456 NavigateAndCommit(url1
);
3457 NavigateAndCommit(url2
);
3458 NavigateAndCommit(url3
);
3459 controller
.GoBack();
3460 contents()->CommitPendingNavigation();
3462 contents()->ExpectSetHistoryLengthAndPrune(
3463 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(1)), 0,
3464 controller
.GetEntryAtIndex(1)->GetPageID());
3466 controller
.PruneAllButVisible();
3468 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3469 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url2
);
3472 // Test call to PruneAllButVisible for a pending entry that is not yet in the
3474 TEST_F(NavigationControllerTest
, PruneAllButVisibleForPendingNotInList
) {
3475 NavigationControllerImpl
& controller
= controller_impl();
3476 const GURL
url1("http://foo/1");
3477 const GURL
url2("http://foo/2");
3478 const GURL
url3("http://foo/3");
3480 NavigateAndCommit(url1
);
3481 NavigateAndCommit(url2
);
3483 // Create a pending entry that is not in the entry list.
3485 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
3486 EXPECT_TRUE(controller
.GetPendingEntry());
3487 EXPECT_EQ(2, controller
.GetEntryCount());
3489 contents()->ExpectSetHistoryLengthAndPrune(
3490 NULL
, 0, controller
.GetPendingEntry()->GetPageID());
3491 controller
.PruneAllButVisible();
3493 // We should only have the last committed and pending entries at this point,
3494 // and the pending entry should still not be in the entry list.
3495 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
3496 EXPECT_EQ(url2
, controller
.GetEntryAtIndex(0)->GetURL());
3497 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3498 EXPECT_TRUE(controller
.GetPendingEntry());
3499 EXPECT_EQ(1, controller
.GetEntryCount());
3501 // Try to commit the pending entry.
3502 test_rvh()->SendNavigate(2, url3
);
3503 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3504 EXPECT_FALSE(controller
.GetPendingEntry());
3505 EXPECT_EQ(2, controller
.GetEntryCount());
3506 EXPECT_EQ(url3
, controller
.GetEntryAtIndex(1)->GetURL());
3509 // Test to ensure that when we do a history navigation back to the current
3510 // committed page (e.g., going forward to a slow-loading page, then pressing
3511 // the back button), we just stop the navigation to prevent the throbber from
3512 // running continuously. Otherwise, the RenderViewHost forces the throbber to
3513 // start, but WebKit essentially ignores the navigation and never sends a
3514 // message to stop the throbber.
3515 TEST_F(NavigationControllerTest
, StopOnHistoryNavigationToCurrentPage
) {
3516 NavigationControllerImpl
& controller
= controller_impl();
3517 const GURL
url0("http://foo/0");
3518 const GURL
url1("http://foo/1");
3520 NavigateAndCommit(url0
);
3521 NavigateAndCommit(url1
);
3523 // Go back to the original page, then forward to the slow page, then back
3524 controller
.GoBack();
3525 contents()->CommitPendingNavigation();
3527 controller
.GoForward();
3528 EXPECT_EQ(1, controller
.GetPendingEntryIndex());
3530 controller
.GoBack();
3531 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3534 TEST_F(NavigationControllerTest
, IsInitialNavigation
) {
3535 NavigationControllerImpl
& controller
= controller_impl();
3536 TestNotificationTracker notifications
;
3537 RegisterForAllNavNotifications(¬ifications
, &controller
);
3540 EXPECT_TRUE(controller
.IsInitialNavigation());
3542 // After commit, it stays false.
3543 const GURL
url1("http://foo1");
3544 test_rvh()->SendNavigate(0, url1
);
3545 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
3546 navigation_entry_committed_counter_
= 0;
3547 EXPECT_FALSE(controller
.IsInitialNavigation());
3549 // After starting a new navigation, it stays false.
3550 const GURL
url2("http://foo2");
3552 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
3555 // Check that the favicon is not reused across a client redirect.
3556 // (crbug.com/28515)
3557 TEST_F(NavigationControllerTest
, ClearFaviconOnRedirect
) {
3558 const GURL
kPageWithFavicon("http://withfavicon.html");
3559 const GURL
kPageWithoutFavicon("http://withoutfavicon.html");
3560 const GURL
kIconURL("http://withfavicon.ico");
3561 const gfx::Image kDefaultFavicon
= FaviconStatus().image
;
3563 NavigationControllerImpl
& controller
= controller_impl();
3564 TestNotificationTracker notifications
;
3565 RegisterForAllNavNotifications(¬ifications
, &controller
);
3567 test_rvh()->SendNavigate(0, kPageWithFavicon
);
3568 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
3569 navigation_entry_committed_counter_
= 0;
3571 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
3573 EXPECT_EQ(kPageWithFavicon
, entry
->GetURL());
3575 // Simulate Chromium having set the favicon for |kPageWithFavicon|.
3576 content::FaviconStatus
& favicon_status
= entry
->GetFavicon();
3577 favicon_status
.image
= CreateImage(SK_ColorWHITE
);
3578 favicon_status
.url
= kIconURL
;
3579 favicon_status
.valid
= true;
3580 EXPECT_FALSE(DoImagesMatch(kDefaultFavicon
, entry
->GetFavicon().image
));
3582 test_rvh()->SendNavigateWithTransition(
3584 kPageWithoutFavicon
,
3585 PAGE_TRANSITION_CLIENT_REDIRECT
);
3586 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
3587 navigation_entry_committed_counter_
= 0;
3589 entry
= controller
.GetLastCommittedEntry();
3591 EXPECT_EQ(kPageWithoutFavicon
, entry
->GetURL());
3593 EXPECT_TRUE(DoImagesMatch(kDefaultFavicon
, entry
->GetFavicon().image
));
3596 // Check that the favicon is not cleared for NavigationEntries which were
3597 // previously navigated to.
3598 TEST_F(NavigationControllerTest
, BackNavigationDoesNotClearFavicon
) {
3599 const GURL
kUrl1("http://www.a.com/1");
3600 const GURL
kUrl2("http://www.a.com/2");
3601 const GURL
kIconURL("http://www.a.com/1/favicon.ico");
3603 NavigationControllerImpl
& controller
= controller_impl();
3604 TestNotificationTracker notifications
;
3605 RegisterForAllNavNotifications(¬ifications
, &controller
);
3607 test_rvh()->SendNavigate(0, kUrl1
);
3608 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
3609 navigation_entry_committed_counter_
= 0;
3611 // Simulate Chromium having set the favicon for |kUrl1|.
3612 gfx::Image favicon_image
= CreateImage(SK_ColorWHITE
);
3613 content::NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
3615 content::FaviconStatus
& favicon_status
= entry
->GetFavicon();
3616 favicon_status
.image
= favicon_image
;
3617 favicon_status
.url
= kIconURL
;
3618 favicon_status
.valid
= true;
3620 // Navigate to another page and go back to the original page.
3621 test_rvh()->SendNavigate(1, kUrl2
);
3622 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
3623 navigation_entry_committed_counter_
= 0;
3624 test_rvh()->SendNavigateWithTransition(
3627 PAGE_TRANSITION_FORWARD_BACK
);
3628 EXPECT_EQ(1U, navigation_entry_committed_counter_
);
3629 navigation_entry_committed_counter_
= 0;
3631 // Verify that the favicon for the page at |kUrl1| was not cleared.
3632 entry
= controller
.GetEntryAtIndex(0);
3634 EXPECT_EQ(kUrl1
, entry
->GetURL());
3635 EXPECT_TRUE(DoImagesMatch(favicon_image
, entry
->GetFavicon().image
));
3638 // The test crashes on android: http://crbug.com/170449
3639 #if defined(OS_ANDROID)
3640 #define MAYBE_PurgeScreenshot DISABLED_PurgeScreenshot
3642 #define MAYBE_PurgeScreenshot PurgeScreenshot
3644 // Tests that screenshot are purged correctly.
3645 TEST_F(NavigationControllerTest
, MAYBE_PurgeScreenshot
) {
3646 NavigationControllerImpl
& controller
= controller_impl();
3648 NavigationEntryImpl
* entry
;
3650 // Navigate enough times to make sure that some screenshots are purged.
3651 for (int i
= 0; i
< 12; ++i
) {
3652 const GURL
url(base::StringPrintf("http://foo%d/", i
));
3653 NavigateAndCommit(url
);
3654 EXPECT_EQ(i
, controller
.GetCurrentEntryIndex());
3657 MockScreenshotManager
* screenshot_manager
=
3658 new MockScreenshotManager(&controller
);
3659 controller
.SetScreenshotManager(screenshot_manager
);
3660 for (int i
= 0; i
< controller
.GetEntryCount(); ++i
) {
3661 entry
= NavigationEntryImpl::FromNavigationEntry(
3662 controller
.GetEntryAtIndex(i
));
3663 screenshot_manager
->TakeScreenshotFor(entry
);
3664 EXPECT_TRUE(entry
->screenshot().get());
3667 NavigateAndCommit(GURL("https://foo/"));
3668 EXPECT_EQ(13, controller
.GetEntryCount());
3669 entry
= NavigationEntryImpl::FromNavigationEntry(
3670 controller
.GetEntryAtIndex(11));
3671 screenshot_manager
->TakeScreenshotFor(entry
);
3673 for (int i
= 0; i
< 2; ++i
) {
3674 entry
= NavigationEntryImpl::FromNavigationEntry(
3675 controller
.GetEntryAtIndex(i
));
3676 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
3680 for (int i
= 2; i
< controller
.GetEntryCount() - 1; ++i
) {
3681 entry
= NavigationEntryImpl::FromNavigationEntry(
3682 controller
.GetEntryAtIndex(i
));
3683 EXPECT_TRUE(entry
->screenshot().get()) << "Screenshot not found for " << i
;
3686 // Navigate to index 5 and then try to assign screenshot to all entries.
3687 controller
.GoToIndex(5);
3688 contents()->CommitPendingNavigation();
3689 EXPECT_EQ(5, controller
.GetCurrentEntryIndex());
3690 for (int i
= 0; i
< controller
.GetEntryCount() - 1; ++i
) {
3691 entry
= NavigationEntryImpl::FromNavigationEntry(
3692 controller
.GetEntryAtIndex(i
));
3693 screenshot_manager
->TakeScreenshotFor(entry
);
3696 for (int i
= 10; i
<= 12; ++i
) {
3697 entry
= NavigationEntryImpl::FromNavigationEntry(
3698 controller
.GetEntryAtIndex(i
));
3699 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
3701 screenshot_manager
->TakeScreenshotFor(entry
);
3704 // Navigate to index 7 and assign screenshot to all entries.
3705 controller
.GoToIndex(7);
3706 contents()->CommitPendingNavigation();
3707 EXPECT_EQ(7, controller
.GetCurrentEntryIndex());
3708 for (int i
= 0; i
< controller
.GetEntryCount() - 1; ++i
) {
3709 entry
= NavigationEntryImpl::FromNavigationEntry(
3710 controller
.GetEntryAtIndex(i
));
3711 screenshot_manager
->TakeScreenshotFor(entry
);
3714 for (int i
= 0; i
< 2; ++i
) {
3715 entry
= NavigationEntryImpl::FromNavigationEntry(
3716 controller
.GetEntryAtIndex(i
));
3717 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
3721 // Clear all screenshots.
3722 EXPECT_EQ(13, controller
.GetEntryCount());
3723 EXPECT_EQ(10, screenshot_manager
->GetScreenshotCount());
3724 controller
.ClearAllScreenshots();
3725 EXPECT_EQ(0, screenshot_manager
->GetScreenshotCount());
3726 for (int i
= 0; i
< controller
.GetEntryCount(); ++i
) {
3727 entry
= NavigationEntryImpl::FromNavigationEntry(
3728 controller
.GetEntryAtIndex(i
));
3729 EXPECT_FALSE(entry
->screenshot().get()) << "Screenshot " << i
3734 // Test that the navigation controller clears its session history when a
3735 // navigation commits with the clear history list flag set.
3736 TEST_F(NavigationControllerTest
, ClearHistoryList
) {
3737 const GURL
url1("http://foo1");
3738 const GURL
url2("http://foo2");
3739 const GURL
url3("http://foo3");
3740 const GURL
url4("http://foo4");
3742 NavigationControllerImpl
& controller
= controller_impl();
3744 // Create a session history with three entries, second entry is active.
3745 NavigateAndCommit(url1
);
3746 NavigateAndCommit(url2
);
3747 NavigateAndCommit(url3
);
3748 controller
.GoBack();
3749 contents()->CommitPendingNavigation();
3750 EXPECT_EQ(3, controller
.GetEntryCount());
3751 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
3753 // Create a new pending navigation, and indicate that the session history
3754 // should be cleared.
3755 NavigationController::LoadURLParams
params(url4
);
3756 params
.should_clear_history_list
= true;
3757 controller
.LoadURLWithParams(params
);
3759 // Verify that the pending entry correctly indicates that the session history
3760 // should be cleared.
3761 NavigationEntryImpl
* entry
=
3762 NavigationEntryImpl::FromNavigationEntry(
3763 controller
.GetPendingEntry());
3765 EXPECT_TRUE(entry
->should_clear_history_list());
3767 // Assume that the RV correctly cleared its history and commit the navigation.
3768 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost())->
3769 set_simulate_history_list_was_cleared(true);
3770 contents()->CommitPendingNavigation();
3772 // Verify that the NavigationController's session history was correctly
3774 EXPECT_EQ(1, controller
.GetEntryCount());
3775 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
3776 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
3777 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
3778 EXPECT_FALSE(controller
.CanGoBack());
3779 EXPECT_FALSE(controller
.CanGoForward());
3780 EXPECT_EQ(url4
, controller
.GetActiveEntry()->GetURL());
3783 /* TODO(brettw) These test pass on my local machine but fail on the XP buildbot
3784 (but not Vista) cleaning up the directory after they run.
3785 This should be fixed.
3787 // NavigationControllerHistoryTest ---------------------------------------------
3789 class NavigationControllerHistoryTest : public NavigationControllerTest {
3791 NavigationControllerHistoryTest()
3792 : url0("http://foo1"),
3793 url1("http://foo1"),
3794 url2("http://foo1"),
3795 profile_manager_(NULL) {
3798 virtual ~NavigationControllerHistoryTest() {
3799 // Prevent our base class from deleting the profile since profile's
3800 // lifetime is managed by profile_manager_.
3801 STLDeleteElements(&windows_);
3804 // testing::Test overrides.
3805 virtual void SetUp() {
3806 NavigationControllerTest::SetUp();
3808 // Force the session service to be created.
3809 SessionService* service = new SessionService(profile());
3810 SessionServiceFactory::SetForTestProfile(profile(), service);
3811 service->SetWindowType(window_id, Browser::TYPE_TABBED);
3812 service->SetWindowBounds(window_id, gfx::Rect(0, 1, 2, 3), false);
3813 service->SetTabIndexInWindow(window_id,
3814 controller.session_id(), 0);
3815 controller.SetWindowID(window_id);
3817 session_helper_.SetService(service);
3820 virtual void TearDown() {
3821 // Release profile's reference to the session service. Otherwise the file
3822 // will still be open and we won't be able to delete the directory below.
3823 session_helper_.ReleaseService(); // profile owns this
3824 SessionServiceFactory::SetForTestProfile(profile(), NULL);
3826 // Make sure we wait for history to shut down before continuing. The task
3827 // we add will cause our message loop to quit once it is destroyed.
3828 HistoryService* history = HistoryServiceFactory::GetForProfiles(
3829 profile(), Profile::IMPLICIT_ACCESS);
3831 history->SetOnBackendDestroyTask(base::MessageLoop::QuitClosure());
3832 base::MessageLoop::current()->Run();
3835 // Do normal cleanup before deleting the profile directory below.
3836 NavigationControllerTest::TearDown();
3838 ASSERT_TRUE(base::DeleteFile(test_dir_, true));
3839 ASSERT_FALSE(base::PathExists(test_dir_));
3842 // Deletes the current profile manager and creates a new one. Indirectly this
3843 // shuts down the history database and reopens it.
3844 void ReopenDatabase() {
3845 session_helper_.SetService(NULL);
3846 SessionServiceFactory::SetForTestProfile(profile(), NULL);
3848 SessionService* service = new SessionService(profile());
3849 SessionServiceFactory::SetForTestProfile(profile(), service);
3850 session_helper_.SetService(service);
3853 void GetLastSession() {
3854 SessionServiceFactory::GetForProfile(profile())->TabClosed(
3855 controller.window_id(), controller.session_id(), false);
3860 session_helper_.ReadWindows(&windows_);
3863 CancelableRequestConsumer consumer;
3865 // URLs for testing.
3870 std::vector<SessionWindow*> windows_;
3872 SessionID window_id;
3874 SessionServiceTestHelper session_helper_;
3877 ProfileManager* profile_manager_;
3878 base::FilePath test_dir_;
3881 // A basic test case. Navigates to a single url, and make sure the history
3883 TEST_F(NavigationControllerHistoryTest, Basic) {
3884 NavigationControllerImpl& controller = controller_impl();
3885 controller.LoadURL(url0, GURL(), PAGE_TRANSITION_LINK);
3886 test_rvh()->SendNavigate(0, url0);
3890 session_helper_.AssertSingleWindowWithSingleTab(windows_, 1);
3891 session_helper_.AssertTabEquals(0, 0, 1, *(windows_[0]->tabs[0]));
3892 TabNavigation nav1(0, url0, GURL(), string16(),
3893 webkit_glue::CreateHistoryStateForURL(url0),
3894 PAGE_TRANSITION_LINK);
3895 session_helper_.AssertNavigationEquals(nav1,
3896 windows_[0]->tabs[0]->navigations[0]);
3899 // Navigates to three urls, then goes back and make sure the history database
3901 TEST_F(NavigationControllerHistoryTest, NavigationThenBack) {
3902 NavigationControllerImpl& controller = controller_impl();
3903 test_rvh()->SendNavigate(0, url0);
3904 test_rvh()->SendNavigate(1, url1);
3905 test_rvh()->SendNavigate(2, url2);
3907 controller.GoBack();
3908 test_rvh()->SendNavigate(1, url1);
3912 session_helper_.AssertSingleWindowWithSingleTab(windows_, 3);
3913 session_helper_.AssertTabEquals(0, 1, 3, *(windows_[0]->tabs[0]));
3915 TabNavigation nav(0, url0, GURL(), string16(),
3916 webkit_glue::CreateHistoryStateForURL(url0),
3917 PAGE_TRANSITION_LINK);
3918 session_helper_.AssertNavigationEquals(nav,
3919 windows_[0]->tabs[0]->navigations[0]);
3921 session_helper_.AssertNavigationEquals(nav,
3922 windows_[0]->tabs[0]->navigations[1]);
3924 session_helper_.AssertNavigationEquals(nav,
3925 windows_[0]->tabs[0]->navigations[2]);
3928 // Navigates to three urls, then goes back twice, then loads a new url.
3929 TEST_F(NavigationControllerHistoryTest, NavigationPruning) {
3930 NavigationControllerImpl& controller = controller_impl();
3931 test_rvh()->SendNavigate(0, url0);
3932 test_rvh()->SendNavigate(1, url1);
3933 test_rvh()->SendNavigate(2, url2);
3935 controller.GoBack();
3936 test_rvh()->SendNavigate(1, url1);
3938 controller.GoBack();
3939 test_rvh()->SendNavigate(0, url0);
3941 test_rvh()->SendNavigate(3, url2);
3943 // Now have url0, and url2.
3947 session_helper_.AssertSingleWindowWithSingleTab(windows_, 2);
3948 session_helper_.AssertTabEquals(0, 1, 2, *(windows_[0]->tabs[0]));
3950 TabNavigation nav(0, url0, GURL(), string16(),
3951 webkit_glue::CreateHistoryStateForURL(url0),
3952 PAGE_TRANSITION_LINK);
3953 session_helper_.AssertNavigationEquals(nav,
3954 windows_[0]->tabs[0]->navigations[0]);
3956 session_helper_.AssertNavigationEquals(nav,
3957 windows_[0]->tabs[0]->navigations[1]);
3961 } // namespace content