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/string_util.h"
12 #include "base/time.h"
13 #include "base/utf_string_conversions.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/test_web_contents.h"
27 #include "content/browser/web_contents/web_contents_impl.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/test/mock_render_process_host.h"
36 #include "content/public/test/test_notification_tracker.h"
37 #include "net/base/net_util.h"
38 #include "skia/ext/platform_canvas.h"
39 #include "testing/gtest/include/gtest/gtest.h"
40 #include "webkit/glue/glue_serialize.h"
46 // Creates an image with a 1x1 SkBitmap of the specified |color|.
47 gfx::Image
CreateImage(SkColor color
) {
49 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, 1, 1);
51 bitmap
.eraseColor(color
);
52 return gfx::Image::CreateFrom1xBitmap(bitmap
);
55 // Returns true if images |a| and |b| have the same pixel data.
56 bool DoImagesMatch(const gfx::Image
& a
, const gfx::Image
& b
) {
57 // Assume that if the 1x bitmaps match, the images match.
58 SkBitmap a_bitmap
= a
.AsBitmap();
59 SkBitmap b_bitmap
= b
.AsBitmap();
61 if (a_bitmap
.width() != b_bitmap
.width() ||
62 a_bitmap
.height() != b_bitmap
.height()) {
65 SkAutoLockPixels
a_bitmap_lock(a_bitmap
);
66 SkAutoLockPixels
b_bitmap_lock(b_bitmap
);
67 return memcmp(a_bitmap
.getPixels(),
69 a_bitmap
.getSize()) == 0;
76 // TimeSmoother tests ----------------------------------------------------------
78 // With no duplicates, GetSmoothedTime should be the identity
80 TEST(TimeSmoother
, Basic
) {
81 NavigationControllerImpl::TimeSmoother smoother
;
82 for (int64 i
= 1; i
< 1000; ++i
) {
83 base::Time t
= base::Time::FromInternalValue(i
);
84 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
88 // With a single duplicate and timestamps thereafter increasing by one
89 // microsecond, the smoothed time should always be one behind.
90 TEST(TimeSmoother
, SingleDuplicate
) {
91 NavigationControllerImpl::TimeSmoother smoother
;
92 base::Time t
= base::Time::FromInternalValue(1);
93 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
94 for (int64 i
= 1; i
< 1000; ++i
) {
95 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1);
96 t
= base::Time::FromInternalValue(i
);
97 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
101 // With k duplicates and timestamps thereafter increasing by one
102 // microsecond, the smoothed time should always be k behind.
103 TEST(TimeSmoother
, ManyDuplicates
) {
104 const int64 kNumDuplicates
= 100;
105 NavigationControllerImpl::TimeSmoother smoother
;
106 base::Time t
= base::Time::FromInternalValue(1);
107 for (int64 i
= 0; i
< kNumDuplicates
; ++i
) {
108 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1);
109 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
111 for (int64 i
= 1; i
< 1000; ++i
) {
112 base::Time expected_t
=
113 base::Time::FromInternalValue(i
+ kNumDuplicates
);
114 t
= base::Time::FromInternalValue(i
);
115 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
119 // If the clock jumps far back enough after a run of duplicates, it
120 // should immediately jump to that value.
121 TEST(TimeSmoother
, ClockBackwardsJump
) {
122 const int64 kNumDuplicates
= 100;
123 NavigationControllerImpl::TimeSmoother smoother
;
124 base::Time t
= base::Time::FromInternalValue(1000);
125 for (int64 i
= 0; i
< kNumDuplicates
; ++i
) {
126 base::Time expected_t
= base::Time::FromInternalValue(i
+ 1000);
127 EXPECT_EQ(expected_t
, smoother
.GetSmoothedTime(t
));
129 t
= base::Time::FromInternalValue(500);
130 EXPECT_EQ(t
, smoother
.GetSmoothedTime(t
));
133 // NavigationControllerTest ----------------------------------------------------
135 class NavigationControllerTest
: public RenderViewHostImplTestHarness
{
137 NavigationControllerTest() {}
139 NavigationControllerImpl
& controller_impl() {
140 return static_cast<NavigationControllerImpl
&>(controller());
144 void RegisterForAllNavNotifications(TestNotificationTracker
* tracker
,
145 NavigationController
* controller
) {
146 tracker
->ListenFor(NOTIFICATION_NAV_ENTRY_COMMITTED
,
147 Source
<NavigationController
>(controller
));
148 tracker
->ListenFor(NOTIFICATION_NAV_LIST_PRUNED
,
149 Source
<NavigationController
>(controller
));
150 tracker
->ListenFor(NOTIFICATION_NAV_ENTRY_CHANGED
,
151 Source
<NavigationController
>(controller
));
154 SiteInstance
* GetSiteInstanceFromEntry(NavigationEntry
* entry
) {
155 return NavigationEntryImpl::FromNavigationEntry(entry
)->site_instance();
158 class TestWebContentsDelegate
: public WebContentsDelegate
{
160 explicit TestWebContentsDelegate() :
161 navigation_state_change_count_(0) {}
163 int navigation_state_change_count() {
164 return navigation_state_change_count_
;
167 // Keep track of whether the tab has notified us of a navigation state change.
168 virtual void NavigationStateChanged(const WebContents
* source
,
169 unsigned changed_flags
) {
170 navigation_state_change_count_
++;
174 // The number of times NavigationStateChanged has been called.
175 int navigation_state_change_count_
;
178 // -----------------------------------------------------------------------------
180 TEST_F(NavigationControllerTest
, Defaults
) {
181 NavigationControllerImpl
& controller
= controller_impl();
183 EXPECT_FALSE(controller
.GetPendingEntry());
184 EXPECT_FALSE(controller
.GetActiveEntry());
185 EXPECT_FALSE(controller
.GetVisibleEntry());
186 EXPECT_FALSE(controller
.GetLastCommittedEntry());
187 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
188 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), -1);
189 EXPECT_EQ(controller
.GetEntryCount(), 0);
190 EXPECT_FALSE(controller
.CanGoBack());
191 EXPECT_FALSE(controller
.CanGoForward());
194 TEST_F(NavigationControllerTest
, GoToOffset
) {
195 NavigationControllerImpl
& controller
= controller_impl();
196 TestNotificationTracker notifications
;
197 RegisterForAllNavNotifications(¬ifications
, &controller
);
199 const int kNumUrls
= 5;
200 std::vector
<GURL
> urls(kNumUrls
);
201 for (int i
= 0; i
< kNumUrls
; ++i
) {
202 urls
[i
] = GURL(base::StringPrintf("http://www.a.com/%d", i
));
205 test_rvh()->SendNavigate(0, urls
[0]);
206 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
207 EXPECT_EQ(urls
[0], controller
.GetActiveEntry()->GetVirtualURL());
208 EXPECT_FALSE(controller
.CanGoBack());
209 EXPECT_FALSE(controller
.CanGoForward());
210 EXPECT_FALSE(controller
.CanGoToOffset(1));
212 for (int i
= 1; i
<= 4; ++i
) {
213 test_rvh()->SendNavigate(i
, urls
[i
]);
214 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
215 EXPECT_EQ(urls
[i
], controller
.GetActiveEntry()->GetVirtualURL());
216 EXPECT_TRUE(controller
.CanGoToOffset(-i
));
217 EXPECT_FALSE(controller
.CanGoToOffset(-(i
+ 1)));
218 EXPECT_FALSE(controller
.CanGoToOffset(1));
221 // We have loaded 5 pages, and are currently at the last-loaded page.
225 GO_TO_MIDDLE_PAGE
= -2,
228 GO_TO_BEGINNING
= -2,
233 const int test_offsets
[NUM_TESTS
] = {
241 for (int test
= 0; test
< NUM_TESTS
; ++test
) {
242 int offset
= test_offsets
[test
];
243 controller
.GoToOffset(offset
);
245 // Check that the GoToOffset will land on the expected page.
246 EXPECT_EQ(urls
[url_index
], controller
.GetPendingEntry()->GetVirtualURL());
247 test_rvh()->SendNavigate(url_index
, urls
[url_index
]);
248 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
249 // Check that we can go to any valid offset into the history.
250 for (size_t j
= 0; j
< urls
.size(); ++j
)
251 EXPECT_TRUE(controller
.CanGoToOffset(j
- url_index
));
252 // Check that we can't go beyond the beginning or end of the history.
253 EXPECT_FALSE(controller
.CanGoToOffset(-(url_index
+ 1)));
254 EXPECT_FALSE(controller
.CanGoToOffset(urls
.size() - url_index
));
258 TEST_F(NavigationControllerTest
, LoadURL
) {
259 NavigationControllerImpl
& controller
= controller_impl();
260 TestNotificationTracker notifications
;
261 RegisterForAllNavNotifications(¬ifications
, &controller
);
263 const GURL
url1("http://foo1");
264 const GURL
url2("http://foo2");
266 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
267 // Creating a pending notification should not have issued any of the
268 // notifications we're listening for.
269 EXPECT_EQ(0U, notifications
.size());
271 // The load should now be pending.
272 EXPECT_EQ(controller
.GetEntryCount(), 0);
273 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), -1);
274 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
275 EXPECT_FALSE(controller
.GetLastCommittedEntry());
276 ASSERT_TRUE(controller
.GetPendingEntry());
277 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetActiveEntry());
278 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetVisibleEntry());
279 EXPECT_FALSE(controller
.CanGoBack());
280 EXPECT_FALSE(controller
.CanGoForward());
281 EXPECT_EQ(contents()->GetMaxPageID(), -1);
283 // The timestamp should not have been set yet.
284 EXPECT_TRUE(controller
.GetPendingEntry()->GetTimestamp().is_null());
286 // We should have gotten no notifications from the preceeding checks.
287 EXPECT_EQ(0U, notifications
.size());
289 test_rvh()->SendNavigate(0, url1
);
290 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
292 // The load should now be committed.
293 EXPECT_EQ(controller
.GetEntryCount(), 1);
294 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
295 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
296 EXPECT_TRUE(controller
.GetLastCommittedEntry());
297 EXPECT_FALSE(controller
.GetPendingEntry());
298 ASSERT_TRUE(controller
.GetActiveEntry());
299 EXPECT_EQ(controller
.GetActiveEntry(), controller
.GetVisibleEntry());
300 EXPECT_FALSE(controller
.CanGoBack());
301 EXPECT_FALSE(controller
.CanGoForward());
302 EXPECT_EQ(contents()->GetMaxPageID(), 0);
304 // The timestamp should have been set.
305 EXPECT_FALSE(controller
.GetActiveEntry()->GetTimestamp().is_null());
308 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
310 // The load should now be pending.
311 EXPECT_EQ(controller
.GetEntryCount(), 1);
312 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
313 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
314 EXPECT_TRUE(controller
.GetLastCommittedEntry());
315 ASSERT_TRUE(controller
.GetPendingEntry());
316 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetActiveEntry());
317 EXPECT_EQ(controller
.GetPendingEntry(), controller
.GetVisibleEntry());
318 // TODO(darin): maybe this should really be true?
319 EXPECT_FALSE(controller
.CanGoBack());
320 EXPECT_FALSE(controller
.CanGoForward());
321 EXPECT_EQ(contents()->GetMaxPageID(), 0);
323 EXPECT_TRUE(controller
.GetPendingEntry()->GetTimestamp().is_null());
325 // Simulate the beforeunload ack for the cross-site transition, and then the
327 test_rvh()->SendShouldCloseACK(true);
328 static_cast<TestRenderViewHost
*>(
329 contents()->GetPendingRenderViewHost())->SendNavigate(1, url2
);
330 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
332 // The load should now be committed.
333 EXPECT_EQ(controller
.GetEntryCount(), 2);
334 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
335 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
336 EXPECT_TRUE(controller
.GetLastCommittedEntry());
337 EXPECT_FALSE(controller
.GetPendingEntry());
338 ASSERT_TRUE(controller
.GetActiveEntry());
339 EXPECT_EQ(controller
.GetActiveEntry(), controller
.GetVisibleEntry());
340 EXPECT_TRUE(controller
.CanGoBack());
341 EXPECT_FALSE(controller
.CanGoForward());
342 EXPECT_EQ(contents()->GetMaxPageID(), 1);
344 EXPECT_FALSE(controller
.GetActiveEntry()->GetTimestamp().is_null());
349 base::Time
GetFixedTime(base::Time time
) {
355 TEST_F(NavigationControllerTest
, LoadURLSameTime
) {
356 NavigationControllerImpl
& controller
= controller_impl();
357 TestNotificationTracker notifications
;
358 RegisterForAllNavNotifications(¬ifications
, &controller
);
360 // Set the clock to always return a timestamp of 1.
361 controller
.SetGetTimestampCallbackForTest(
362 base::Bind(&GetFixedTime
, base::Time::FromInternalValue(1)));
364 const GURL
url1("http://foo1");
365 const GURL
url2("http://foo2");
367 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
369 test_rvh()->SendNavigate(0, url1
);
370 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
373 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
375 // Simulate the beforeunload ack for the cross-site transition, and then the
377 test_rvh()->SendShouldCloseACK(true);
378 test_rvh()->SendNavigate(1, url2
);
379 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
381 // The two loads should now be committed.
382 ASSERT_EQ(controller
.GetEntryCount(), 2);
384 // Timestamps should be distinct despite the clock returning the
387 controller
.GetEntryAtIndex(0)->GetTimestamp().ToInternalValue());
389 controller
.GetEntryAtIndex(1)->GetTimestamp().ToInternalValue());
392 void CheckNavigationEntryMatchLoadParams(
393 NavigationController::LoadURLParams
& load_params
,
394 NavigationEntryImpl
* entry
) {
395 EXPECT_EQ(load_params
.url
, entry
->GetURL());
396 EXPECT_EQ(load_params
.referrer
.url
, entry
->GetReferrer().url
);
397 EXPECT_EQ(load_params
.referrer
.policy
, entry
->GetReferrer().policy
);
398 EXPECT_EQ(load_params
.transition_type
, entry
->GetTransitionType());
399 EXPECT_EQ(load_params
.extra_headers
, entry
->extra_headers());
401 EXPECT_EQ(load_params
.is_renderer_initiated
, entry
->is_renderer_initiated());
402 EXPECT_EQ(load_params
.base_url_for_data_url
, entry
->GetBaseURLForDataURL());
403 if (!load_params
.virtual_url_for_data_url
.is_empty()) {
404 EXPECT_EQ(load_params
.virtual_url_for_data_url
, entry
->GetVirtualURL());
406 if (NavigationController::UA_OVERRIDE_INHERIT
!=
407 load_params
.override_user_agent
) {
408 bool should_override
= (NavigationController::UA_OVERRIDE_TRUE
==
409 load_params
.override_user_agent
);
410 EXPECT_EQ(should_override
, entry
->GetIsOverridingUserAgent());
412 EXPECT_EQ(load_params
.browser_initiated_post_data
,
413 entry
->GetBrowserInitiatedPostData());
414 EXPECT_EQ(load_params
.transferred_global_request_id
,
415 entry
->transferred_global_request_id());
418 TEST_F(NavigationControllerTest
, LoadURLWithParams
) {
419 NavigationControllerImpl
& controller
= controller_impl();
421 NavigationController::LoadURLParams
load_params(GURL("http://foo"));
422 load_params
.referrer
=
423 Referrer(GURL("http://referrer"), WebKit::WebReferrerPolicyDefault
);
424 load_params
.transition_type
= PAGE_TRANSITION_GENERATED
;
425 load_params
.extra_headers
= "content-type: text/plain";
426 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
427 load_params
.is_renderer_initiated
= true;
428 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
429 load_params
.transferred_global_request_id
= GlobalRequestID(2,3);
431 controller
.LoadURLWithParams(load_params
);
432 NavigationEntryImpl
* entry
=
433 NavigationEntryImpl::FromNavigationEntry(
434 controller
.GetPendingEntry());
436 // The timestamp should not have been set yet.
438 EXPECT_TRUE(entry
->GetTimestamp().is_null());
440 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
443 TEST_F(NavigationControllerTest
, LoadURLWithExtraParams_Data
) {
444 NavigationControllerImpl
& controller
= controller_impl();
446 NavigationController::LoadURLParams
load_params(
447 GURL("data:text/html,dataurl"));
448 load_params
.load_type
= NavigationController::LOAD_TYPE_DATA
;
449 load_params
.base_url_for_data_url
= GURL("http://foo");
450 load_params
.virtual_url_for_data_url
= GURL("about:blank");
451 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_FALSE
;
453 controller
.LoadURLWithParams(load_params
);
454 NavigationEntryImpl
* entry
=
455 NavigationEntryImpl::FromNavigationEntry(
456 controller
.GetPendingEntry());
458 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
461 TEST_F(NavigationControllerTest
, LoadURLWithExtraParams_HttpPost
) {
462 NavigationControllerImpl
& controller
= controller_impl();
464 NavigationController::LoadURLParams
load_params(GURL("https://posturl"));
465 load_params
.transition_type
= PAGE_TRANSITION_TYPED
;
466 load_params
.load_type
=
467 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST
;
468 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
471 const unsigned char* raw_data
=
472 reinterpret_cast<const unsigned char*>("d\n\0a2");
473 const int length
= 5;
474 std::vector
<unsigned char> post_data_vector(raw_data
, raw_data
+length
);
475 scoped_refptr
<base::RefCountedBytes
> data
=
476 base::RefCountedBytes::TakeVector(&post_data_vector
);
477 load_params
.browser_initiated_post_data
= data
.get();
479 controller
.LoadURLWithParams(load_params
);
480 NavigationEntryImpl
* entry
=
481 NavigationEntryImpl::FromNavigationEntry(
482 controller
.GetPendingEntry());
484 CheckNavigationEntryMatchLoadParams(load_params
, entry
);
487 // Tests what happens when the same page is loaded again. Should not create a
488 // new session history entry. This is what happens when you press enter in the
489 // URL bar to reload: a pending entry is created and then it is discarded when
490 // the load commits (because WebCore didn't actually make a new entry).
491 TEST_F(NavigationControllerTest
, LoadURL_SamePage
) {
492 NavigationControllerImpl
& controller
= controller_impl();
493 TestNotificationTracker notifications
;
494 RegisterForAllNavNotifications(¬ifications
, &controller
);
496 const GURL
url1("http://foo1");
498 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
499 EXPECT_EQ(0U, notifications
.size());
500 test_rvh()->SendNavigate(0, url1
);
501 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
503 ASSERT_TRUE(controller
.GetActiveEntry());
504 const base::Time timestamp
= controller
.GetActiveEntry()->GetTimestamp();
505 EXPECT_FALSE(timestamp
.is_null());
507 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
508 EXPECT_EQ(0U, notifications
.size());
509 test_rvh()->SendNavigate(0, url1
);
510 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
512 // We should not have produced a new session history entry.
513 EXPECT_EQ(controller
.GetEntryCount(), 1);
514 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
515 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
516 EXPECT_TRUE(controller
.GetLastCommittedEntry());
517 EXPECT_FALSE(controller
.GetPendingEntry());
518 ASSERT_TRUE(controller
.GetActiveEntry());
519 EXPECT_FALSE(controller
.CanGoBack());
520 EXPECT_FALSE(controller
.CanGoForward());
522 // The timestamp should have been updated.
524 // TODO(akalin): Change this EXPECT_GE (and other similar ones) to
525 // EXPECT_GT once we guarantee that timestamps are unique.
526 EXPECT_GE(controller
.GetActiveEntry()->GetTimestamp(), timestamp
);
529 // Tests loading a URL but discarding it before the load commits.
530 TEST_F(NavigationControllerTest
, LoadURL_Discarded
) {
531 NavigationControllerImpl
& controller
= controller_impl();
532 TestNotificationTracker notifications
;
533 RegisterForAllNavNotifications(¬ifications
, &controller
);
535 const GURL
url1("http://foo1");
536 const GURL
url2("http://foo2");
538 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
539 EXPECT_EQ(0U, notifications
.size());
540 test_rvh()->SendNavigate(0, url1
);
541 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
543 ASSERT_TRUE(controller
.GetActiveEntry());
544 const base::Time timestamp
= controller
.GetActiveEntry()->GetTimestamp();
545 EXPECT_FALSE(timestamp
.is_null());
547 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
548 controller
.DiscardNonCommittedEntries();
549 EXPECT_EQ(0U, notifications
.size());
551 // Should not have produced a new session history entry.
552 EXPECT_EQ(controller
.GetEntryCount(), 1);
553 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
554 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
555 EXPECT_TRUE(controller
.GetLastCommittedEntry());
556 EXPECT_FALSE(controller
.GetPendingEntry());
557 ASSERT_TRUE(controller
.GetActiveEntry());
558 EXPECT_FALSE(controller
.CanGoBack());
559 EXPECT_FALSE(controller
.CanGoForward());
561 // Timestamp should not have changed.
562 EXPECT_EQ(timestamp
, controller
.GetActiveEntry()->GetTimestamp());
565 // Tests navigations that come in unrequested. This happens when the user
566 // navigates from the web page, and here we test that there is no pending entry.
567 TEST_F(NavigationControllerTest
, LoadURL_NoPending
) {
568 NavigationControllerImpl
& controller
= controller_impl();
569 TestNotificationTracker notifications
;
570 RegisterForAllNavNotifications(¬ifications
, &controller
);
572 // First make an existing committed entry.
573 const GURL
kExistingURL1("http://eh");
575 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
576 test_rvh()->SendNavigate(0, kExistingURL1
);
577 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
579 // Do a new navigation without making a pending one.
580 const GURL
kNewURL("http://see");
581 test_rvh()->SendNavigate(99, kNewURL
);
583 // There should no longer be any pending entry, and the third navigation we
584 // just made should be committed.
585 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
586 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
587 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
588 EXPECT_EQ(kNewURL
, controller
.GetActiveEntry()->GetURL());
591 // Tests navigating to a new URL when there is a new pending navigation that is
592 // not the one that just loaded. This will happen if the user types in a URL to
593 // somewhere slow, and then navigates the current page before the typed URL
595 TEST_F(NavigationControllerTest
, LoadURL_NewPending
) {
596 NavigationControllerImpl
& controller
= controller_impl();
597 TestNotificationTracker notifications
;
598 RegisterForAllNavNotifications(¬ifications
, &controller
);
600 // First make an existing committed entry.
601 const GURL
kExistingURL1("http://eh");
603 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
604 test_rvh()->SendNavigate(0, kExistingURL1
);
605 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
607 // Make a pending entry to somewhere new.
608 const GURL
kExistingURL2("http://bee");
610 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
611 EXPECT_EQ(0U, notifications
.size());
613 // After the beforeunload but before it commits, do a new navigation.
614 test_rvh()->SendShouldCloseACK(true);
615 const GURL
kNewURL("http://see");
616 static_cast<TestRenderViewHost
*>(
617 contents()->GetPendingRenderViewHost())->SendNavigate(3, kNewURL
);
619 // There should no longer be any pending entry, and the third navigation we
620 // just made should be committed.
621 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
622 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
623 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
624 EXPECT_EQ(kNewURL
, controller
.GetActiveEntry()->GetURL());
627 // Tests navigating to a new URL when there is a pending back/forward
628 // navigation. This will happen if the user hits back, but before that commits,
629 // they navigate somewhere new.
630 TEST_F(NavigationControllerTest
, LoadURL_ExistingPending
) {
631 NavigationControllerImpl
& controller
= controller_impl();
632 TestNotificationTracker notifications
;
633 RegisterForAllNavNotifications(¬ifications
, &controller
);
635 // First make some history.
636 const GURL
kExistingURL1("http://foo/eh");
638 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
639 test_rvh()->SendNavigate(0, kExistingURL1
);
640 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
642 const GURL
kExistingURL2("http://foo/bee");
644 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
645 test_rvh()->SendNavigate(1, kExistingURL2
);
646 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
648 // Now make a pending back/forward navigation. The zeroth entry should be
651 EXPECT_EQ(0U, notifications
.size());
652 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
653 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
655 // Before that commits, do a new navigation.
656 const GURL
kNewURL("http://foo/see");
657 LoadCommittedDetails details
;
658 test_rvh()->SendNavigate(3, kNewURL
);
660 // There should no longer be any pending entry, and the third navigation we
661 // just made should be committed.
662 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
663 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
664 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
665 EXPECT_EQ(kNewURL
, controller
.GetActiveEntry()->GetURL());
668 // Tests navigating to an existing URL when there is a pending new navigation.
669 // This will happen if the user enters a URL, but before that commits, the
670 // current page fires history.back().
671 TEST_F(NavigationControllerTest
, LoadURL_BackPreemptsPending
) {
672 NavigationControllerImpl
& controller
= controller_impl();
673 TestNotificationTracker notifications
;
674 RegisterForAllNavNotifications(¬ifications
, &controller
);
676 // First make some history.
677 const GURL
kExistingURL1("http://foo/eh");
679 kExistingURL1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
680 test_rvh()->SendNavigate(0, kExistingURL1
);
681 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
683 const GURL
kExistingURL2("http://foo/bee");
685 kExistingURL2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
686 test_rvh()->SendNavigate(1, kExistingURL2
);
687 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
689 // Now make a pending new navigation.
690 const GURL
kNewURL("http://foo/see");
692 kNewURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
693 EXPECT_EQ(0U, notifications
.size());
694 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
695 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
697 // Before that commits, a back navigation from the renderer commits.
698 test_rvh()->SendNavigate(0, kExistingURL1
);
700 // There should no longer be any pending entry, and the back navigation we
701 // just made should be committed.
702 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
703 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
704 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
705 EXPECT_EQ(kExistingURL1
, controller
.GetActiveEntry()->GetURL());
708 // Tests an ignored navigation when there is a pending new navigation.
709 // This will happen if the user enters a URL, but before that commits, the
710 // current blank page reloads. See http://crbug.com/77507.
711 TEST_F(NavigationControllerTest
, LoadURL_IgnorePreemptsPending
) {
712 NavigationControllerImpl
& controller
= controller_impl();
713 TestNotificationTracker notifications
;
714 RegisterForAllNavNotifications(¬ifications
, &controller
);
716 // Set a WebContentsDelegate to listen for state changes.
717 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
718 EXPECT_FALSE(contents()->GetDelegate());
719 contents()->SetDelegate(delegate
.get());
721 // Without any navigations, the renderer starts at about:blank.
722 const GURL
kExistingURL("about:blank");
724 // Now make a pending new navigation.
725 const GURL
kNewURL("http://eh");
727 kNewURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
728 EXPECT_EQ(0U, notifications
.size());
729 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
730 EXPECT_TRUE(controller
.GetPendingEntry());
731 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
732 EXPECT_EQ(1, delegate
->navigation_state_change_count());
734 // Before that commits, a document.write and location.reload can cause the
735 // renderer to send a FrameNavigate with page_id -1.
736 test_rvh()->SendNavigate(-1, kExistingURL
);
738 // This should clear the pending entry and notify of a navigation state
739 // change, so that we do not keep displaying kNewURL.
740 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
741 EXPECT_FALSE(controller
.GetPendingEntry());
742 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
743 EXPECT_EQ(2, delegate
->navigation_state_change_count());
745 contents()->SetDelegate(NULL
);
748 // Tests that the pending entry state is correct after an abort.
749 // We do not want to clear the pending entry, so that the user doesn't
750 // lose a typed URL. (See http://crbug.com/9682.)
751 TEST_F(NavigationControllerTest
, LoadURL_AbortDoesntCancelPending
) {
752 NavigationControllerImpl
& controller
= controller_impl();
753 TestNotificationTracker notifications
;
754 RegisterForAllNavNotifications(¬ifications
, &controller
);
756 // Set a WebContentsDelegate to listen for state changes.
757 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
758 EXPECT_FALSE(contents()->GetDelegate());
759 contents()->SetDelegate(delegate
.get());
761 // Without any navigations, the renderer starts at about:blank.
762 const GURL
kExistingURL("about:blank");
764 // Now make a pending new navigation.
765 const GURL
kNewURL("http://eh");
767 kNewURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
768 EXPECT_EQ(0U, notifications
.size());
769 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
770 EXPECT_TRUE(controller
.GetPendingEntry());
771 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
772 EXPECT_EQ(1, delegate
->navigation_state_change_count());
774 // It may abort before committing, if it's a download or due to a stop or
775 // a new navigation from the user.
776 ViewHostMsg_DidFailProvisionalLoadWithError_Params params
;
778 params
.is_main_frame
= true;
779 params
.error_code
= net::ERR_ABORTED
;
780 params
.error_description
= string16();
781 params
.url
= kNewURL
;
782 params
.showing_repost_interstitial
= false;
783 test_rvh()->OnMessageReceived(
784 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
787 // This should not clear the pending entry or notify of a navigation state
788 // change, so that we keep displaying kNewURL (until the user clears it).
789 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
790 EXPECT_TRUE(controller
.GetPendingEntry());
791 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
792 EXPECT_EQ(1, delegate
->navigation_state_change_count());
794 contents()->SetDelegate(NULL
);
797 // Tests that the pending URL is not visible during a renderer-initiated
798 // redirect and abort. See http://crbug.com/83031.
799 TEST_F(NavigationControllerTest
, LoadURL_RedirectAbortDoesntShowPendingURL
) {
800 NavigationControllerImpl
& controller
= controller_impl();
801 TestNotificationTracker notifications
;
802 RegisterForAllNavNotifications(¬ifications
, &controller
);
804 // Set a WebContentsDelegate to listen for state changes.
805 scoped_ptr
<TestWebContentsDelegate
> delegate(new TestWebContentsDelegate());
806 EXPECT_FALSE(contents()->GetDelegate());
807 contents()->SetDelegate(delegate
.get());
809 // Without any navigations, the renderer starts at about:blank.
810 const GURL
kExistingURL("about:blank");
812 // Now make a pending new navigation, initiated by the renderer.
813 const GURL
kNewURL("http://eh");
814 NavigationController::LoadURLParams
load_url_params(kNewURL
);
815 load_url_params
.transition_type
= PAGE_TRANSITION_TYPED
;
816 load_url_params
.is_renderer_initiated
= true;
817 controller
.LoadURLWithParams(load_url_params
);
818 EXPECT_EQ(0U, notifications
.size());
819 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
820 EXPECT_TRUE(controller
.GetPendingEntry());
821 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
822 EXPECT_EQ(1, delegate
->navigation_state_change_count());
824 // There should be no visible entry (resulting in about:blank in the
825 // omnibox), because it was renderer-initiated and there's no last committed
827 EXPECT_FALSE(controller
.GetVisibleEntry());
829 // Now the navigation redirects.
830 const GURL
kRedirectURL("http://bee");
831 test_rvh()->OnMessageReceived(
832 ViewHostMsg_DidRedirectProvisionalLoad(0, // routing_id
833 -1, // pending page_id
835 kRedirectURL
)); // new url
837 // We don't want to change the NavigationEntry's url, in case it cancels.
838 // Prevents regression of http://crbug.com/77786.
839 EXPECT_EQ(kNewURL
, controller
.GetPendingEntry()->GetURL());
841 // It may abort before committing, if it's a download or due to a stop or
842 // a new navigation from the user.
843 ViewHostMsg_DidFailProvisionalLoadWithError_Params params
;
845 params
.is_main_frame
= true;
846 params
.error_code
= net::ERR_ABORTED
;
847 params
.error_description
= string16();
848 params
.url
= kRedirectURL
;
849 params
.showing_repost_interstitial
= false;
850 test_rvh()->OnMessageReceived(
851 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
854 // This should not clear the pending entry or notify of a navigation state
856 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
857 EXPECT_TRUE(controller
.GetPendingEntry());
858 EXPECT_EQ(-1, controller
.GetLastCommittedEntryIndex());
859 EXPECT_EQ(1, delegate
->navigation_state_change_count());
861 // There should be no visible entry (resulting in about:blank in the
862 // omnibox), ensuring no spoof is possible.
863 EXPECT_FALSE(controller
.GetVisibleEntry());
865 contents()->SetDelegate(NULL
);
868 TEST_F(NavigationControllerTest
, Reload
) {
869 NavigationControllerImpl
& controller
= controller_impl();
870 TestNotificationTracker notifications
;
871 RegisterForAllNavNotifications(¬ifications
, &controller
);
873 const GURL
url1("http://foo1");
875 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
876 EXPECT_EQ(0U, notifications
.size());
877 test_rvh()->SendNavigate(0, url1
);
878 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
879 ASSERT_TRUE(controller
.GetActiveEntry());
880 controller
.GetActiveEntry()->SetTitle(ASCIIToUTF16("Title"));
881 controller
.Reload(true);
882 EXPECT_EQ(0U, notifications
.size());
884 const base::Time timestamp
= controller
.GetActiveEntry()->GetTimestamp();
885 EXPECT_FALSE(timestamp
.is_null());
887 // The reload is pending.
888 EXPECT_EQ(controller
.GetEntryCount(), 1);
889 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
890 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
891 EXPECT_TRUE(controller
.GetLastCommittedEntry());
892 EXPECT_TRUE(controller
.GetPendingEntry());
893 EXPECT_FALSE(controller
.CanGoBack());
894 EXPECT_FALSE(controller
.CanGoForward());
895 // Make sure the title has been cleared (will be redrawn just after reload).
896 // Avoids a stale cached title when the new page being reloaded has no title.
897 // See http://crbug.com/96041.
898 EXPECT_TRUE(controller
.GetActiveEntry()->GetTitle().empty());
900 test_rvh()->SendNavigate(0, url1
);
901 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
903 // Now the reload is committed.
904 EXPECT_EQ(controller
.GetEntryCount(), 1);
905 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
906 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
907 EXPECT_TRUE(controller
.GetLastCommittedEntry());
908 EXPECT_FALSE(controller
.GetPendingEntry());
909 EXPECT_FALSE(controller
.CanGoBack());
910 EXPECT_FALSE(controller
.CanGoForward());
912 // The timestamp should have been updated.
913 ASSERT_TRUE(controller
.GetActiveEntry());
914 EXPECT_GE(controller
.GetActiveEntry()->GetTimestamp(), timestamp
);
917 // Tests what happens when a reload navigation produces a new page.
918 TEST_F(NavigationControllerTest
, Reload_GeneratesNewPage
) {
919 NavigationControllerImpl
& controller
= controller_impl();
920 TestNotificationTracker notifications
;
921 RegisterForAllNavNotifications(¬ifications
, &controller
);
923 const GURL
url1("http://foo1");
924 const GURL
url2("http://foo2");
926 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
927 test_rvh()->SendNavigate(0, url1
);
928 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
930 controller
.Reload(true);
931 EXPECT_EQ(0U, notifications
.size());
933 test_rvh()->SendNavigate(1, url2
);
934 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
936 // Now the reload is committed.
937 EXPECT_EQ(controller
.GetEntryCount(), 2);
938 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
939 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
940 EXPECT_TRUE(controller
.GetLastCommittedEntry());
941 EXPECT_FALSE(controller
.GetPendingEntry());
942 EXPECT_TRUE(controller
.CanGoBack());
943 EXPECT_FALSE(controller
.CanGoForward());
946 class TestNavigationObserver
: public RenderViewHostObserver
{
948 TestNavigationObserver(RenderViewHost
* render_view_host
)
949 : RenderViewHostObserver(render_view_host
) {
952 const GURL
& navigated_url() const {
953 return navigated_url_
;
957 virtual void Navigate(const GURL
& url
) OVERRIDE
{
958 navigated_url_
= url
;
965 #if !defined(OS_ANDROID) // http://crbug.com/157428
966 TEST_F(NavigationControllerTest
, ReloadOriginalRequestURL
) {
967 NavigationControllerImpl
& controller
= controller_impl();
968 TestNotificationTracker notifications
;
969 RegisterForAllNavNotifications(¬ifications
, &controller
);
970 TestNavigationObserver
observer(test_rvh());
972 const GURL
original_url("http://foo1");
973 const GURL
final_url("http://foo2");
975 // Load up the original URL, but get redirected.
977 original_url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
978 EXPECT_EQ(0U, notifications
.size());
979 test_rvh()->SendNavigateWithOriginalRequestURL(0, final_url
, original_url
);
980 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
982 // The NavigationEntry should save both the original URL and the final
984 EXPECT_EQ(original_url
, controller
.GetActiveEntry()->GetOriginalRequestURL());
985 EXPECT_EQ(final_url
, controller
.GetActiveEntry()->GetURL());
987 // Reload using the original URL.
988 controller
.GetActiveEntry()->SetTitle(ASCIIToUTF16("Title"));
989 controller
.ReloadOriginalRequestURL(false);
990 EXPECT_EQ(0U, notifications
.size());
992 // The reload is pending. The request should point to the original URL.
993 EXPECT_EQ(original_url
, observer
.navigated_url());
994 EXPECT_EQ(controller
.GetEntryCount(), 1);
995 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
996 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
997 EXPECT_TRUE(controller
.GetLastCommittedEntry());
998 EXPECT_TRUE(controller
.GetPendingEntry());
999 EXPECT_FALSE(controller
.CanGoBack());
1000 EXPECT_FALSE(controller
.CanGoForward());
1002 // Make sure the title has been cleared (will be redrawn just after reload).
1003 // Avoids a stale cached title when the new page being reloaded has no title.
1004 // See http://crbug.com/96041.
1005 EXPECT_TRUE(controller
.GetActiveEntry()->GetTitle().empty());
1007 // Send that the navigation has proceeded; say it got redirected again.
1008 test_rvh()->SendNavigate(0, final_url
);
1009 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1011 // Now the reload is committed.
1012 EXPECT_EQ(controller
.GetEntryCount(), 1);
1013 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1014 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1015 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1016 EXPECT_FALSE(controller
.GetPendingEntry());
1017 EXPECT_FALSE(controller
.CanGoBack());
1018 EXPECT_FALSE(controller
.CanGoForward());
1021 #endif // !defined(OS_ANDROID)
1023 // Tests what happens when we navigate back successfully
1024 TEST_F(NavigationControllerTest
, Back
) {
1025 NavigationControllerImpl
& controller
= controller_impl();
1026 TestNotificationTracker notifications
;
1027 RegisterForAllNavNotifications(¬ifications
, &controller
);
1029 const GURL
url1("http://foo1");
1030 test_rvh()->SendNavigate(0, url1
);
1031 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1033 const GURL
url2("http://foo2");
1034 test_rvh()->SendNavigate(1, url2
);
1035 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1037 controller
.GoBack();
1038 EXPECT_EQ(0U, notifications
.size());
1040 // We should now have a pending navigation to go back.
1041 EXPECT_EQ(controller
.GetEntryCount(), 2);
1042 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1043 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1044 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1045 EXPECT_TRUE(controller
.GetPendingEntry());
1046 EXPECT_FALSE(controller
.CanGoBack());
1047 EXPECT_FALSE(controller
.CanGoToOffset(-1));
1048 EXPECT_TRUE(controller
.CanGoForward());
1049 EXPECT_TRUE(controller
.CanGoToOffset(1));
1050 EXPECT_FALSE(controller
.CanGoToOffset(2)); // Cannot go foward 2 steps.
1052 // Timestamp for entry 1 should be on or after that of entry 0.
1053 EXPECT_FALSE(controller
.GetEntryAtIndex(0)->GetTimestamp().is_null());
1054 EXPECT_GE(controller
.GetEntryAtIndex(1)->GetTimestamp(),
1055 controller
.GetEntryAtIndex(0)->GetTimestamp());
1057 test_rvh()->SendNavigate(0, url2
);
1058 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1060 // The back navigation completed successfully.
1061 EXPECT_EQ(controller
.GetEntryCount(), 2);
1062 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1063 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1064 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1065 EXPECT_FALSE(controller
.GetPendingEntry());
1066 EXPECT_FALSE(controller
.CanGoBack());
1067 EXPECT_FALSE(controller
.CanGoToOffset(-1));
1068 EXPECT_TRUE(controller
.CanGoForward());
1069 EXPECT_TRUE(controller
.CanGoToOffset(1));
1070 EXPECT_FALSE(controller
.CanGoToOffset(2)); // Cannot go foward 2 steps.
1072 // Timestamp for entry 0 should be on or after that of entry 1
1073 // (since we went back to it).
1074 EXPECT_GE(controller
.GetEntryAtIndex(0)->GetTimestamp(),
1075 controller
.GetEntryAtIndex(1)->GetTimestamp());
1078 // Tests what happens when a back navigation produces a new page.
1079 TEST_F(NavigationControllerTest
, Back_GeneratesNewPage
) {
1080 NavigationControllerImpl
& controller
= controller_impl();
1081 TestNotificationTracker notifications
;
1082 RegisterForAllNavNotifications(¬ifications
, &controller
);
1084 const GURL
url1("http://foo/1");
1085 const GURL
url2("http://foo/2");
1086 const GURL
url3("http://foo/3");
1089 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1090 test_rvh()->SendNavigate(0, url1
);
1091 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1093 controller
.LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1094 test_rvh()->SendNavigate(1, url2
);
1095 EXPECT_TRUE(notifications
.Check1AndReset(
1096 NOTIFICATION_NAV_ENTRY_COMMITTED
));
1098 controller
.GoBack();
1099 EXPECT_EQ(0U, notifications
.size());
1101 // We should now have a pending navigation to go back.
1102 EXPECT_EQ(controller
.GetEntryCount(), 2);
1103 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1104 EXPECT_EQ(controller
.GetPendingEntryIndex(), 0);
1105 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1106 EXPECT_TRUE(controller
.GetPendingEntry());
1107 EXPECT_FALSE(controller
.CanGoBack());
1108 EXPECT_TRUE(controller
.CanGoForward());
1110 test_rvh()->SendNavigate(2, url3
);
1111 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1113 // The back navigation resulted in a completely new navigation.
1114 // TODO(darin): perhaps this behavior will be confusing to users?
1115 EXPECT_EQ(controller
.GetEntryCount(), 3);
1116 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 2);
1117 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1118 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1119 EXPECT_FALSE(controller
.GetPendingEntry());
1120 EXPECT_TRUE(controller
.CanGoBack());
1121 EXPECT_FALSE(controller
.CanGoForward());
1124 // Receives a back message when there is a new pending navigation entry.
1125 TEST_F(NavigationControllerTest
, Back_NewPending
) {
1126 NavigationControllerImpl
& controller
= controller_impl();
1127 TestNotificationTracker notifications
;
1128 RegisterForAllNavNotifications(¬ifications
, &controller
);
1130 const GURL
kUrl1("http://foo1");
1131 const GURL
kUrl2("http://foo2");
1132 const GURL
kUrl3("http://foo3");
1134 // First navigate two places so we have some back history.
1135 test_rvh()->SendNavigate(0, kUrl1
);
1136 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1138 // controller.LoadURL(kUrl2, PAGE_TRANSITION_TYPED);
1139 test_rvh()->SendNavigate(1, kUrl2
);
1140 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1142 // Now start a new pending navigation and go back before it commits.
1143 controller
.LoadURL(kUrl3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1144 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1145 EXPECT_EQ(kUrl3
, controller
.GetPendingEntry()->GetURL());
1146 controller
.GoBack();
1148 // The pending navigation should now be the "back" item and the new one
1150 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
1151 EXPECT_EQ(kUrl1
, controller
.GetPendingEntry()->GetURL());
1154 // Receives a back message when there is a different renavigation already
1156 TEST_F(NavigationControllerTest
, Back_OtherBackPending
) {
1157 NavigationControllerImpl
& controller
= controller_impl();
1158 const GURL
kUrl1("http://foo/1");
1159 const GURL
kUrl2("http://foo/2");
1160 const GURL
kUrl3("http://foo/3");
1162 // First navigate three places so we have some back history.
1163 test_rvh()->SendNavigate(0, kUrl1
);
1164 test_rvh()->SendNavigate(1, kUrl2
);
1165 test_rvh()->SendNavigate(2, kUrl3
);
1167 // With nothing pending, say we get a navigation to the second entry.
1168 test_rvh()->SendNavigate(1, kUrl2
);
1170 // We know all the entries have the same site instance, so we can just grab
1171 // a random one for looking up other entries.
1172 SiteInstance
* site_instance
=
1173 NavigationEntryImpl::FromNavigationEntry(
1174 controller
.GetLastCommittedEntry())->site_instance();
1176 // That second URL should be the last committed and it should have gotten the
1178 EXPECT_EQ(kUrl2
, controller
.GetEntryWithPageID(site_instance
, 1)->GetURL());
1179 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1180 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1182 // Now go forward to the last item again and say it was committed.
1183 controller
.GoForward();
1184 test_rvh()->SendNavigate(2, kUrl3
);
1186 // Now start going back one to the second page. It will be pending.
1187 controller
.GoBack();
1188 EXPECT_EQ(1, controller
.GetPendingEntryIndex());
1189 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1191 // Not synthesize a totally new back event to the first page. This will not
1192 // match the pending one.
1193 test_rvh()->SendNavigate(0, kUrl1
);
1195 // The committed navigation should clear the pending entry.
1196 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
1198 // But the navigated entry should be the last committed.
1199 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1200 EXPECT_EQ(kUrl1
, controller
.GetLastCommittedEntry()->GetURL());
1203 // Tests what happens when we navigate forward successfully.
1204 TEST_F(NavigationControllerTest
, Forward
) {
1205 NavigationControllerImpl
& controller
= controller_impl();
1206 TestNotificationTracker notifications
;
1207 RegisterForAllNavNotifications(¬ifications
, &controller
);
1209 const GURL
url1("http://foo1");
1210 const GURL
url2("http://foo2");
1212 test_rvh()->SendNavigate(0, url1
);
1213 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1215 test_rvh()->SendNavigate(1, url2
);
1216 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1218 controller
.GoBack();
1219 test_rvh()->SendNavigate(0, url1
);
1220 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1222 controller
.GoForward();
1224 // We should now have a pending navigation to go forward.
1225 EXPECT_EQ(controller
.GetEntryCount(), 2);
1226 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1227 EXPECT_EQ(controller
.GetPendingEntryIndex(), 1);
1228 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1229 EXPECT_TRUE(controller
.GetPendingEntry());
1230 EXPECT_TRUE(controller
.CanGoBack());
1231 EXPECT_TRUE(controller
.CanGoToOffset(-1));
1232 EXPECT_FALSE(controller
.CanGoToOffset(-2)); // Cannot go back 2 steps.
1233 EXPECT_FALSE(controller
.CanGoForward());
1234 EXPECT_FALSE(controller
.CanGoToOffset(1));
1236 // Timestamp for entry 0 should be on or after that of entry 1
1237 // (since we went back to it).
1238 EXPECT_FALSE(controller
.GetEntryAtIndex(0)->GetTimestamp().is_null());
1239 EXPECT_GE(controller
.GetEntryAtIndex(0)->GetTimestamp(),
1240 controller
.GetEntryAtIndex(1)->GetTimestamp());
1242 test_rvh()->SendNavigate(1, url2
);
1243 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1245 // The forward navigation completed successfully.
1246 EXPECT_EQ(controller
.GetEntryCount(), 2);
1247 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1248 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1249 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1250 EXPECT_FALSE(controller
.GetPendingEntry());
1251 EXPECT_TRUE(controller
.CanGoBack());
1252 EXPECT_TRUE(controller
.CanGoToOffset(-1));
1253 EXPECT_FALSE(controller
.CanGoToOffset(-2)); // Cannot go back 2 steps.
1254 EXPECT_FALSE(controller
.CanGoForward());
1255 EXPECT_FALSE(controller
.CanGoToOffset(1));
1257 // Timestamp for entry 1 should be on or after that of entry 0
1258 // (since we went forward to it).
1259 EXPECT_GE(controller
.GetEntryAtIndex(1)->GetTimestamp(),
1260 controller
.GetEntryAtIndex(0)->GetTimestamp());
1263 // Tests what happens when a forward navigation produces a new page.
1264 TEST_F(NavigationControllerTest
, Forward_GeneratesNewPage
) {
1265 NavigationControllerImpl
& controller
= controller_impl();
1266 TestNotificationTracker notifications
;
1267 RegisterForAllNavNotifications(¬ifications
, &controller
);
1269 const GURL
url1("http://foo1");
1270 const GURL
url2("http://foo2");
1271 const GURL
url3("http://foo3");
1273 test_rvh()->SendNavigate(0, url1
);
1274 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1275 test_rvh()->SendNavigate(1, url2
);
1276 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1278 controller
.GoBack();
1279 test_rvh()->SendNavigate(0, url1
);
1280 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1282 controller
.GoForward();
1283 EXPECT_EQ(0U, notifications
.size());
1285 // Should now have a pending navigation to go forward.
1286 EXPECT_EQ(controller
.GetEntryCount(), 2);
1287 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1288 EXPECT_EQ(controller
.GetPendingEntryIndex(), 1);
1289 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1290 EXPECT_TRUE(controller
.GetPendingEntry());
1291 EXPECT_TRUE(controller
.CanGoBack());
1292 EXPECT_FALSE(controller
.CanGoForward());
1294 test_rvh()->SendNavigate(2, url3
);
1295 EXPECT_TRUE(notifications
.Check2AndReset(
1296 NOTIFICATION_NAV_LIST_PRUNED
,
1297 NOTIFICATION_NAV_ENTRY_COMMITTED
));
1299 EXPECT_EQ(controller
.GetEntryCount(), 2);
1300 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1301 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1302 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1303 EXPECT_FALSE(controller
.GetPendingEntry());
1304 EXPECT_TRUE(controller
.CanGoBack());
1305 EXPECT_FALSE(controller
.CanGoForward());
1308 // Two consequent navigation for the same URL entered in should be considered
1309 // as SAME_PAGE navigation even when we are redirected to some other page.
1310 TEST_F(NavigationControllerTest
, Redirect
) {
1311 NavigationControllerImpl
& controller
= controller_impl();
1312 TestNotificationTracker notifications
;
1313 RegisterForAllNavNotifications(¬ifications
, &controller
);
1315 const GURL
url1("http://foo1");
1316 const GURL
url2("http://foo2"); // Redirection target
1319 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1321 EXPECT_EQ(0U, notifications
.size());
1322 test_rvh()->SendNavigate(0, url2
);
1323 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1326 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1328 EXPECT_TRUE(controller
.GetPendingEntry());
1329 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1330 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
1332 ViewHostMsg_FrameNavigate_Params params
;
1335 params
.transition
= PAGE_TRANSITION_SERVER_REDIRECT
;
1336 params
.redirects
.push_back(GURL("http://foo1"));
1337 params
.redirects
.push_back(GURL("http://foo2"));
1338 params
.should_update_history
= false;
1339 params
.gesture
= NavigationGestureAuto
;
1340 params
.is_post
= false;
1341 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url2
));
1343 LoadCommittedDetails details
;
1345 EXPECT_EQ(0U, notifications
.size());
1346 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1347 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1349 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_SAME_PAGE
);
1350 EXPECT_EQ(controller
.GetEntryCount(), 1);
1351 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1352 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1353 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1354 EXPECT_FALSE(controller
.GetPendingEntry());
1355 EXPECT_EQ(url2
, controller
.GetActiveEntry()->GetURL());
1357 EXPECT_FALSE(controller
.CanGoBack());
1358 EXPECT_FALSE(controller
.CanGoForward());
1361 // Similar to Redirect above, but the first URL is requested by POST,
1362 // the second URL is requested by GET. NavigationEntry::has_post_data_
1363 // must be cleared. http://crbug.com/21245
1364 TEST_F(NavigationControllerTest
, PostThenRedirect
) {
1365 NavigationControllerImpl
& controller
= controller_impl();
1366 TestNotificationTracker notifications
;
1367 RegisterForAllNavNotifications(¬ifications
, &controller
);
1369 const GURL
url1("http://foo1");
1370 const GURL
url2("http://foo2"); // Redirection target
1372 // First request as POST
1373 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1374 controller
.GetActiveEntry()->SetHasPostData(true);
1376 EXPECT_EQ(0U, notifications
.size());
1377 test_rvh()->SendNavigate(0, url2
);
1378 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1381 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1383 EXPECT_TRUE(controller
.GetPendingEntry());
1384 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1385 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
1387 ViewHostMsg_FrameNavigate_Params params
;
1390 params
.transition
= PAGE_TRANSITION_SERVER_REDIRECT
;
1391 params
.redirects
.push_back(GURL("http://foo1"));
1392 params
.redirects
.push_back(GURL("http://foo2"));
1393 params
.should_update_history
= false;
1394 params
.gesture
= NavigationGestureAuto
;
1395 params
.is_post
= false;
1396 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url2
));
1398 LoadCommittedDetails details
;
1400 EXPECT_EQ(0U, notifications
.size());
1401 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1402 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1404 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_SAME_PAGE
);
1405 EXPECT_EQ(controller
.GetEntryCount(), 1);
1406 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1407 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1408 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1409 EXPECT_FALSE(controller
.GetPendingEntry());
1410 EXPECT_EQ(url2
, controller
.GetActiveEntry()->GetURL());
1411 EXPECT_FALSE(controller
.GetActiveEntry()->GetHasPostData());
1413 EXPECT_FALSE(controller
.CanGoBack());
1414 EXPECT_FALSE(controller
.CanGoForward());
1417 // A redirect right off the bat should be a NEW_PAGE.
1418 TEST_F(NavigationControllerTest
, ImmediateRedirect
) {
1419 NavigationControllerImpl
& controller
= controller_impl();
1420 TestNotificationTracker notifications
;
1421 RegisterForAllNavNotifications(¬ifications
, &controller
);
1423 const GURL
url1("http://foo1");
1424 const GURL
url2("http://foo2"); // Redirection target
1427 controller
.LoadURL(url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1429 EXPECT_TRUE(controller
.GetPendingEntry());
1430 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1431 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
1433 ViewHostMsg_FrameNavigate_Params params
;
1436 params
.transition
= PAGE_TRANSITION_SERVER_REDIRECT
;
1437 params
.redirects
.push_back(GURL("http://foo1"));
1438 params
.redirects
.push_back(GURL("http://foo2"));
1439 params
.should_update_history
= false;
1440 params
.gesture
= NavigationGestureAuto
;
1441 params
.is_post
= false;
1442 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url2
));
1444 LoadCommittedDetails details
;
1446 EXPECT_EQ(0U, notifications
.size());
1447 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1448 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1450 EXPECT_TRUE(details
.type
== NAVIGATION_TYPE_NEW_PAGE
);
1451 EXPECT_EQ(controller
.GetEntryCount(), 1);
1452 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
1453 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1454 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1455 EXPECT_FALSE(controller
.GetPendingEntry());
1456 EXPECT_EQ(url2
, controller
.GetActiveEntry()->GetURL());
1458 EXPECT_FALSE(controller
.CanGoBack());
1459 EXPECT_FALSE(controller
.CanGoForward());
1462 // Tests navigation via link click within a subframe. A new navigation entry
1463 // should be created.
1464 TEST_F(NavigationControllerTest
, NewSubframe
) {
1465 NavigationControllerImpl
& controller
= controller_impl();
1466 TestNotificationTracker notifications
;
1467 RegisterForAllNavNotifications(¬ifications
, &controller
);
1469 const GURL
url1("http://foo1");
1470 test_rvh()->SendNavigate(0, url1
);
1471 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1473 const GURL
url2("http://foo2");
1474 ViewHostMsg_FrameNavigate_Params params
;
1477 params
.transition
= PAGE_TRANSITION_MANUAL_SUBFRAME
;
1478 params
.should_update_history
= false;
1479 params
.gesture
= NavigationGestureUser
;
1480 params
.is_post
= false;
1481 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url2
));
1483 LoadCommittedDetails details
;
1484 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1485 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1486 EXPECT_EQ(url1
, details
.previous_url
);
1487 EXPECT_FALSE(details
.is_in_page
);
1488 EXPECT_FALSE(details
.is_main_frame
);
1490 // The new entry should be appended.
1491 EXPECT_EQ(2, controller
.GetEntryCount());
1493 // New entry should refer to the new page, but the old URL (entries only
1494 // reflect the toplevel URL).
1495 EXPECT_EQ(url1
, details
.entry
->GetURL());
1496 EXPECT_EQ(params
.page_id
, details
.entry
->GetPageID());
1499 // Some pages create a popup, then write an iframe into it. This causes a
1500 // subframe navigation without having any committed entry. Such navigations
1501 // just get thrown on the ground, but we shouldn't crash.
1502 TEST_F(NavigationControllerTest
, SubframeOnEmptyPage
) {
1503 NavigationControllerImpl
& controller
= controller_impl();
1504 TestNotificationTracker notifications
;
1505 RegisterForAllNavNotifications(¬ifications
, &controller
);
1507 // Navigation controller currently has no entries.
1508 const GURL
url("http://foo2");
1509 ViewHostMsg_FrameNavigate_Params params
;
1512 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
1513 params
.should_update_history
= false;
1514 params
.gesture
= NavigationGestureAuto
;
1515 params
.is_post
= false;
1516 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url
));
1518 LoadCommittedDetails details
;
1519 EXPECT_FALSE(controller
.RendererDidNavigate(params
, &details
));
1520 EXPECT_EQ(0U, notifications
.size());
1523 // Auto subframes are ones the page loads automatically like ads. They should
1524 // not create new navigation entries.
1525 TEST_F(NavigationControllerTest
, AutoSubframe
) {
1526 NavigationControllerImpl
& controller
= controller_impl();
1527 TestNotificationTracker notifications
;
1528 RegisterForAllNavNotifications(¬ifications
, &controller
);
1530 const GURL
url1("http://foo1");
1531 test_rvh()->SendNavigate(0, url1
);
1532 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1534 const GURL
url2("http://foo2");
1535 ViewHostMsg_FrameNavigate_Params params
;
1538 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
1539 params
.should_update_history
= false;
1540 params
.gesture
= NavigationGestureUser
;
1541 params
.is_post
= false;
1542 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url2
));
1544 // Navigating should do nothing.
1545 LoadCommittedDetails details
;
1546 EXPECT_FALSE(controller
.RendererDidNavigate(params
, &details
));
1547 EXPECT_EQ(0U, notifications
.size());
1549 // There should still be only one entry.
1550 EXPECT_EQ(1, controller
.GetEntryCount());
1553 // Tests navigation and then going back to a subframe navigation.
1554 TEST_F(NavigationControllerTest
, BackSubframe
) {
1555 NavigationControllerImpl
& controller
= controller_impl();
1556 TestNotificationTracker notifications
;
1557 RegisterForAllNavNotifications(¬ifications
, &controller
);
1560 const GURL
url1("http://foo1");
1561 test_rvh()->SendNavigate(0, url1
);
1562 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1564 // First manual subframe navigation.
1565 const GURL
url2("http://foo2");
1566 ViewHostMsg_FrameNavigate_Params params
;
1569 params
.transition
= PAGE_TRANSITION_MANUAL_SUBFRAME
;
1570 params
.should_update_history
= false;
1571 params
.gesture
= NavigationGestureUser
;
1572 params
.is_post
= false;
1573 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url2
));
1575 // This should generate a new entry.
1576 LoadCommittedDetails details
;
1577 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1578 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1579 EXPECT_EQ(2, controller
.GetEntryCount());
1581 // Second manual subframe navigation should also make a new entry.
1582 const GURL
url3("http://foo3");
1585 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1586 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1587 EXPECT_EQ(3, controller
.GetEntryCount());
1588 EXPECT_EQ(2, controller
.GetCurrentEntryIndex());
1591 controller
.GoBack();
1594 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1595 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1596 EXPECT_EQ(3, controller
.GetEntryCount());
1597 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
1599 // Go back one more.
1600 controller
.GoBack();
1603 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1604 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1605 EXPECT_EQ(3, controller
.GetEntryCount());
1606 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
1609 TEST_F(NavigationControllerTest
, LinkClick
) {
1610 NavigationControllerImpl
& controller
= controller_impl();
1611 TestNotificationTracker notifications
;
1612 RegisterForAllNavNotifications(¬ifications
, &controller
);
1614 const GURL
url1("http://foo1");
1615 const GURL
url2("http://foo2");
1617 test_rvh()->SendNavigate(0, url1
);
1618 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1620 test_rvh()->SendNavigate(1, url2
);
1621 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1623 // Should not have produced a new session history entry.
1624 EXPECT_EQ(controller
.GetEntryCount(), 2);
1625 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
1626 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
1627 EXPECT_TRUE(controller
.GetLastCommittedEntry());
1628 EXPECT_FALSE(controller
.GetPendingEntry());
1629 EXPECT_TRUE(controller
.CanGoBack());
1630 EXPECT_FALSE(controller
.CanGoForward());
1633 TEST_F(NavigationControllerTest
, InPage
) {
1634 NavigationControllerImpl
& controller
= controller_impl();
1635 TestNotificationTracker notifications
;
1636 RegisterForAllNavNotifications(¬ifications
, &controller
);
1639 const GURL
url1("http://foo");
1640 test_rvh()->SendNavigate(0, url1
);
1641 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1643 // Ensure main page navigation to same url respects the was_within_same_page
1644 // hint provided in the params.
1645 ViewHostMsg_FrameNavigate_Params self_params
;
1646 self_params
.page_id
= 0;
1647 self_params
.url
= url1
;
1648 self_params
.transition
= PAGE_TRANSITION_LINK
;
1649 self_params
.should_update_history
= false;
1650 self_params
.gesture
= NavigationGestureUser
;
1651 self_params
.is_post
= false;
1652 self_params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url1
));
1653 self_params
.was_within_same_page
= true;
1655 LoadCommittedDetails details
;
1656 EXPECT_TRUE(controller
.RendererDidNavigate(self_params
, &details
));
1657 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1658 EXPECT_TRUE(details
.is_in_page
);
1659 EXPECT_TRUE(details
.did_replace_entry
);
1660 EXPECT_EQ(1, controller
.GetEntryCount());
1662 // Fragment navigation to a new page_id.
1663 const GURL
url2("http://foo#a");
1664 ViewHostMsg_FrameNavigate_Params params
;
1667 params
.transition
= PAGE_TRANSITION_LINK
;
1668 params
.should_update_history
= false;
1669 params
.gesture
= NavigationGestureUser
;
1670 params
.is_post
= false;
1671 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url2
));
1673 // This should generate a new entry.
1674 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1675 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1676 EXPECT_TRUE(details
.is_in_page
);
1677 EXPECT_FALSE(details
.did_replace_entry
);
1678 EXPECT_EQ(2, controller
.GetEntryCount());
1681 ViewHostMsg_FrameNavigate_Params
back_params(params
);
1682 controller
.GoBack();
1683 back_params
.url
= url1
;
1684 back_params
.page_id
= 0;
1685 EXPECT_TRUE(controller
.RendererDidNavigate(back_params
, &details
));
1686 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1687 // is_in_page is false in that case but should be true.
1688 // See comment in AreURLsInPageNavigation() in navigation_controller.cc
1689 // EXPECT_TRUE(details.is_in_page);
1690 EXPECT_EQ(2, controller
.GetEntryCount());
1691 EXPECT_EQ(0, controller
.GetCurrentEntryIndex());
1692 EXPECT_EQ(back_params
.url
, controller
.GetActiveEntry()->GetURL());
1695 ViewHostMsg_FrameNavigate_Params
forward_params(params
);
1696 controller
.GoForward();
1697 forward_params
.url
= url2
;
1698 forward_params
.page_id
= 1;
1699 EXPECT_TRUE(controller
.RendererDidNavigate(forward_params
, &details
));
1700 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1701 EXPECT_TRUE(details
.is_in_page
);
1702 EXPECT_EQ(2, controller
.GetEntryCount());
1703 EXPECT_EQ(1, controller
.GetCurrentEntryIndex());
1704 EXPECT_EQ(forward_params
.url
,
1705 controller
.GetActiveEntry()->GetURL());
1707 // Now go back and forward again. This is to work around a bug where we would
1708 // compare the incoming URL with the last committed entry rather than the
1709 // one identified by an existing page ID. This would result in the second URL
1710 // losing the reference fragment when you navigate away from it and then back.
1711 controller
.GoBack();
1712 EXPECT_TRUE(controller
.RendererDidNavigate(back_params
, &details
));
1713 controller
.GoForward();
1714 EXPECT_TRUE(controller
.RendererDidNavigate(forward_params
, &details
));
1715 EXPECT_EQ(forward_params
.url
,
1716 controller
.GetActiveEntry()->GetURL());
1718 // Finally, navigate to an unrelated URL to make sure in_page is not sticky.
1719 const GURL
url3("http://bar");
1722 notifications
.Reset();
1723 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1724 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1725 EXPECT_FALSE(details
.is_in_page
);
1726 EXPECT_EQ(3, controller
.GetEntryCount());
1727 EXPECT_EQ(2, controller
.GetCurrentEntryIndex());
1730 TEST_F(NavigationControllerTest
, InPage_Replace
) {
1731 NavigationControllerImpl
& controller
= controller_impl();
1732 TestNotificationTracker notifications
;
1733 RegisterForAllNavNotifications(¬ifications
, &controller
);
1736 const GURL
url1("http://foo");
1737 test_rvh()->SendNavigate(0, url1
);
1738 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1740 // First navigation.
1741 const GURL
url2("http://foo#a");
1742 ViewHostMsg_FrameNavigate_Params params
;
1743 params
.page_id
= 0; // Same page_id
1745 params
.transition
= PAGE_TRANSITION_LINK
;
1746 params
.should_update_history
= false;
1747 params
.gesture
= NavigationGestureUser
;
1748 params
.is_post
= false;
1749 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url2
));
1751 // This should NOT generate a new entry, nor prune the list.
1752 LoadCommittedDetails details
;
1753 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1754 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1755 EXPECT_TRUE(details
.is_in_page
);
1756 EXPECT_TRUE(details
.did_replace_entry
);
1757 EXPECT_EQ(1, controller
.GetEntryCount());
1760 // Tests for http://crbug.com/40395
1763 // window.location.replace("#a");
1764 // window.location='http://foo3/';
1766 TEST_F(NavigationControllerTest
, ClientRedirectAfterInPageNavigation
) {
1767 NavigationControllerImpl
& controller
= controller_impl();
1768 TestNotificationTracker notifications
;
1769 RegisterForAllNavNotifications(¬ifications
, &controller
);
1771 // Load an initial page.
1773 const GURL
url("http://foo/");
1774 test_rvh()->SendNavigate(0, url
);
1775 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1778 // Navigate to a new page.
1780 const GURL
url("http://foo2/");
1781 test_rvh()->SendNavigate(1, url
);
1782 controller
.DocumentLoadedInFrame();
1783 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1786 // Navigate within the page.
1788 const GURL
url("http://foo2/#a");
1789 ViewHostMsg_FrameNavigate_Params params
;
1790 params
.page_id
= 1; // Same page_id
1792 params
.transition
= PAGE_TRANSITION_LINK
;
1793 params
.redirects
.push_back(url
);
1794 params
.should_update_history
= true;
1795 params
.gesture
= NavigationGestureUnknown
;
1796 params
.is_post
= false;
1797 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url
));
1799 // This should NOT generate a new entry, nor prune the list.
1800 LoadCommittedDetails details
;
1801 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1802 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1803 EXPECT_TRUE(details
.is_in_page
);
1804 EXPECT_TRUE(details
.did_replace_entry
);
1805 EXPECT_EQ(2, controller
.GetEntryCount());
1808 // Perform a client redirect to a new page.
1810 const GURL
url("http://foo3/");
1811 ViewHostMsg_FrameNavigate_Params params
;
1812 params
.page_id
= 2; // New page_id
1814 params
.transition
= PAGE_TRANSITION_CLIENT_REDIRECT
;
1815 params
.redirects
.push_back(GURL("http://foo2/#a"));
1816 params
.redirects
.push_back(url
);
1817 params
.should_update_history
= true;
1818 params
.gesture
= NavigationGestureUnknown
;
1819 params
.is_post
= false;
1820 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url
));
1822 // This SHOULD generate a new entry.
1823 LoadCommittedDetails details
;
1824 EXPECT_TRUE(controller
.RendererDidNavigate(params
, &details
));
1825 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
1826 EXPECT_FALSE(details
.is_in_page
);
1827 EXPECT_EQ(3, controller
.GetEntryCount());
1830 // Verify that BACK brings us back to http://foo2/.
1832 const GURL
url("http://foo2/");
1833 controller
.GoBack();
1834 test_rvh()->SendNavigate(1, url
);
1835 EXPECT_TRUE(notifications
.Check1AndReset(
1836 NOTIFICATION_NAV_ENTRY_COMMITTED
));
1837 EXPECT_EQ(url
, controller
.GetActiveEntry()->GetURL());
1841 // NotificationObserver implementation used in verifying we've received the
1842 // NOTIFICATION_NAV_LIST_PRUNED method.
1843 class PrunedListener
: public NotificationObserver
{
1845 explicit PrunedListener(NavigationControllerImpl
* controller
)
1846 : notification_count_(0) {
1847 registrar_
.Add(this, NOTIFICATION_NAV_LIST_PRUNED
,
1848 Source
<NavigationController
>(controller
));
1851 virtual void Observe(int type
,
1852 const NotificationSource
& source
,
1853 const NotificationDetails
& details
) {
1854 if (type
== NOTIFICATION_NAV_LIST_PRUNED
) {
1855 notification_count_
++;
1856 details_
= *(Details
<PrunedDetails
>(details
).ptr());
1860 // Number of times NAV_LIST_PRUNED has been observed.
1861 int notification_count_
;
1863 // Details from the last NAV_LIST_PRUNED.
1864 PrunedDetails details_
;
1867 NotificationRegistrar registrar_
;
1869 DISALLOW_COPY_AND_ASSIGN(PrunedListener
);
1872 // Tests that we limit the number of navigation entries created correctly.
1873 TEST_F(NavigationControllerTest
, EnforceMaxNavigationCount
) {
1874 NavigationControllerImpl
& controller
= controller_impl();
1875 size_t original_count
= NavigationControllerImpl::max_entry_count();
1876 const int kMaxEntryCount
= 5;
1878 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
1881 // Load up to the max count, all entries should be there.
1882 for (url_index
= 0; url_index
< kMaxEntryCount
; url_index
++) {
1883 GURL
url(StringPrintf("http://www.a.com/%d", url_index
));
1885 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1886 test_rvh()->SendNavigate(url_index
, url
);
1889 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
1891 // Created a PrunedListener to observe prune notifications.
1892 PrunedListener
listener(&controller
);
1894 // Navigate some more.
1895 GURL
url(StringPrintf("http://www.a.com/%d", url_index
));
1897 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1898 test_rvh()->SendNavigate(url_index
, url
);
1901 // We should have got a pruned navigation.
1902 EXPECT_EQ(1, listener
.notification_count_
);
1903 EXPECT_TRUE(listener
.details_
.from_front
);
1904 EXPECT_EQ(1, listener
.details_
.count
);
1906 // We expect http://www.a.com/0 to be gone.
1907 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
1908 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(),
1909 GURL("http:////www.a.com/1"));
1911 // More navigations.
1912 for (int i
= 0; i
< 3; i
++) {
1913 url
= GURL(StringPrintf("http:////www.a.com/%d", url_index
));
1915 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1916 test_rvh()->SendNavigate(url_index
, url
);
1919 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
1920 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(),
1921 GURL("http:////www.a.com/4"));
1923 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
1926 // Tests that we can do a restore and navigate to the restored entries and
1927 // everything is updated properly. This can be tricky since there is no
1928 // SiteInstance for the entries created initially.
1929 TEST_F(NavigationControllerTest
, RestoreNavigate
) {
1930 // Create a NavigationController with a restored set of tabs.
1931 GURL
url("http://foo");
1932 std::vector
<NavigationEntry
*> entries
;
1933 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
1934 url
, Referrer(), PAGE_TRANSITION_RELOAD
, false, std::string(),
1936 entry
->SetPageID(0);
1937 entry
->SetTitle(ASCIIToUTF16("Title"));
1938 entry
->SetContentState("state");
1939 const base::Time timestamp
= base::Time::Now();
1940 entry
->SetTimestamp(timestamp
);
1941 entries
.push_back(entry
);
1942 scoped_ptr
<WebContentsImpl
> our_contents(static_cast<WebContentsImpl
*>(
1943 WebContents::Create(WebContents::CreateParams(browser_context()))));
1944 NavigationControllerImpl
& our_controller
= our_contents
->GetController();
1945 our_controller
.Restore(
1947 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
1949 ASSERT_EQ(0u, entries
.size());
1951 // Before navigating to the restored entry, it should have a restore_type
1952 // and no SiteInstance.
1953 ASSERT_EQ(1, our_controller
.GetEntryCount());
1954 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
1955 NavigationEntryImpl::FromNavigationEntry(
1956 our_controller
.GetEntryAtIndex(0))->restore_type());
1957 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
1958 our_controller
.GetEntryAtIndex(0))->site_instance());
1960 // After navigating, we should have one entry, and it should be "pending".
1961 // It should now have a SiteInstance and no restore_type.
1962 our_controller
.GoToIndex(0);
1963 EXPECT_EQ(1, our_controller
.GetEntryCount());
1964 EXPECT_EQ(our_controller
.GetEntryAtIndex(0),
1965 our_controller
.GetPendingEntry());
1966 EXPECT_EQ(0, our_controller
.GetEntryAtIndex(0)->GetPageID());
1967 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
1968 NavigationEntryImpl::FromNavigationEntry
1969 (our_controller
.GetEntryAtIndex(0))->restore_type());
1970 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
1971 our_controller
.GetEntryAtIndex(0))->site_instance());
1973 // Timestamp should remain the same before the navigation finishes.
1974 EXPECT_EQ(timestamp
, our_controller
.GetEntryAtIndex(0)->GetTimestamp());
1976 // Say we navigated to that entry.
1977 ViewHostMsg_FrameNavigate_Params params
;
1980 params
.transition
= PAGE_TRANSITION_LINK
;
1981 params
.should_update_history
= false;
1982 params
.gesture
= NavigationGestureUser
;
1983 params
.is_post
= false;
1984 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url
));
1985 LoadCommittedDetails details
;
1986 our_controller
.RendererDidNavigate(params
, &details
);
1988 // There should be no longer any pending entry and one committed one. This
1989 // means that we were able to locate the entry, assign its site instance, and
1990 // commit it properly.
1991 EXPECT_EQ(1, our_controller
.GetEntryCount());
1992 EXPECT_EQ(0, our_controller
.GetLastCommittedEntryIndex());
1993 EXPECT_FALSE(our_controller
.GetPendingEntry());
1995 NavigationEntryImpl::FromNavigationEntry(
1996 our_controller
.GetLastCommittedEntry())->site_instance()->
1998 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
1999 NavigationEntryImpl::FromNavigationEntry(
2000 our_controller
.GetEntryAtIndex(0))->restore_type());
2002 // Timestamp should have been updated.
2003 EXPECT_GE(our_controller
.GetEntryAtIndex(0)->GetTimestamp(), timestamp
);
2006 // Tests that we can still navigate to a restored entry after a different
2007 // navigation fails and clears the pending entry. http://crbug.com/90085
2008 TEST_F(NavigationControllerTest
, RestoreNavigateAfterFailure
) {
2009 // Create a NavigationController with a restored set of tabs.
2010 GURL
url("http://foo");
2011 std::vector
<NavigationEntry
*> entries
;
2012 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
2013 url
, Referrer(), PAGE_TRANSITION_RELOAD
, false, std::string(),
2015 entry
->SetPageID(0);
2016 entry
->SetTitle(ASCIIToUTF16("Title"));
2017 entry
->SetContentState("state");
2018 entries
.push_back(entry
);
2019 scoped_ptr
<WebContentsImpl
> our_contents(static_cast<WebContentsImpl
*>(
2020 WebContents::Create(WebContents::CreateParams(browser_context()))));
2021 NavigationControllerImpl
& our_controller
= our_contents
->GetController();
2022 our_controller
.Restore(
2023 0, NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
, &entries
);
2024 ASSERT_EQ(0u, entries
.size());
2026 // Before navigating to the restored entry, it should have a restore_type
2027 // and no SiteInstance.
2028 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
2029 NavigationEntryImpl::FromNavigationEntry(
2030 our_controller
.GetEntryAtIndex(0))->restore_type());
2031 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
2032 our_controller
.GetEntryAtIndex(0))->site_instance());
2034 // After navigating, we should have one entry, and it should be "pending".
2035 // It should now have a SiteInstance and no restore_type.
2036 our_controller
.GoToIndex(0);
2037 EXPECT_EQ(1, our_controller
.GetEntryCount());
2038 EXPECT_EQ(our_controller
.GetEntryAtIndex(0),
2039 our_controller
.GetPendingEntry());
2040 EXPECT_EQ(0, our_controller
.GetEntryAtIndex(0)->GetPageID());
2041 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2042 NavigationEntryImpl::FromNavigationEntry(
2043 our_controller
.GetEntryAtIndex(0))->restore_type());
2044 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
2045 our_controller
.GetEntryAtIndex(0))->site_instance());
2047 // This pending navigation may have caused a different navigation to fail,
2048 // which causes the pending entry to be cleared.
2049 TestRenderViewHost
* rvh
=
2050 static_cast<TestRenderViewHost
*>(our_contents
->GetRenderViewHost());
2051 ViewHostMsg_DidFailProvisionalLoadWithError_Params fail_load_params
;
2052 fail_load_params
.frame_id
= 1;
2053 fail_load_params
.is_main_frame
= true;
2054 fail_load_params
.error_code
= net::ERR_ABORTED
;
2055 fail_load_params
.error_description
= string16();
2056 fail_load_params
.url
= url
;
2057 fail_load_params
.showing_repost_interstitial
= false;
2058 rvh
->OnMessageReceived(
2059 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
2062 // Now the pending restored entry commits.
2063 ViewHostMsg_FrameNavigate_Params params
;
2066 params
.transition
= PAGE_TRANSITION_LINK
;
2067 params
.should_update_history
= false;
2068 params
.gesture
= NavigationGestureUser
;
2069 params
.is_post
= false;
2070 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url
));
2071 LoadCommittedDetails details
;
2072 our_controller
.RendererDidNavigate(params
, &details
);
2074 // There should be no pending entry and one committed one.
2075 EXPECT_EQ(1, our_controller
.GetEntryCount());
2076 EXPECT_EQ(0, our_controller
.GetLastCommittedEntryIndex());
2077 EXPECT_FALSE(our_controller
.GetPendingEntry());
2079 NavigationEntryImpl::FromNavigationEntry(
2080 our_controller
.GetLastCommittedEntry())->site_instance()->
2082 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE
,
2083 NavigationEntryImpl::FromNavigationEntry(
2084 our_controller
.GetEntryAtIndex(0))->restore_type());
2087 // Make sure that the page type and stuff is correct after an interstitial.
2088 TEST_F(NavigationControllerTest
, Interstitial
) {
2089 NavigationControllerImpl
& controller
= controller_impl();
2090 // First navigate somewhere normal.
2091 const GURL
url1("http://foo");
2093 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2094 test_rvh()->SendNavigate(0, url1
);
2096 // Now navigate somewhere with an interstitial.
2097 const GURL
url2("http://bar");
2099 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2100 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2101 set_page_type(PAGE_TYPE_INTERSTITIAL
);
2103 // At this point the interstitial will be displayed and the load will still
2104 // be pending. If the user continues, the load will commit.
2105 test_rvh()->SendNavigate(1, url2
);
2107 // The page should be a normal page again.
2108 EXPECT_EQ(url2
, controller
.GetLastCommittedEntry()->GetURL());
2109 EXPECT_EQ(PAGE_TYPE_NORMAL
,
2110 controller
.GetLastCommittedEntry()->GetPageType());
2113 TEST_F(NavigationControllerTest
, RemoveEntry
) {
2114 NavigationControllerImpl
& controller
= controller_impl();
2115 const GURL
url1("http://foo/1");
2116 const GURL
url2("http://foo/2");
2117 const GURL
url3("http://foo/3");
2118 const GURL
url4("http://foo/4");
2119 const GURL
url5("http://foo/5");
2120 const GURL
pending_url("http://foo/pending");
2121 const GURL
default_url("http://foo/default");
2124 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2125 test_rvh()->SendNavigate(0, url1
);
2127 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2128 test_rvh()->SendNavigate(1, url2
);
2130 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2131 test_rvh()->SendNavigate(2, url3
);
2133 url4
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2134 test_rvh()->SendNavigate(3, url4
);
2136 url5
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2137 test_rvh()->SendNavigate(4, url5
);
2139 // Try to remove the last entry. Will fail because it is the current entry.
2140 controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1);
2141 EXPECT_EQ(5, controller
.GetEntryCount());
2142 EXPECT_EQ(4, controller
.GetLastCommittedEntryIndex());
2144 // Go back and remove the last entry.
2145 controller
.GoBack();
2146 test_rvh()->SendNavigate(3, url4
);
2147 controller
.RemoveEntryAtIndex(controller
.GetEntryCount() - 1);
2148 EXPECT_EQ(4, controller
.GetEntryCount());
2149 EXPECT_EQ(3, controller
.GetLastCommittedEntryIndex());
2150 EXPECT_FALSE(controller
.GetPendingEntry());
2152 // Remove an entry which is not the last committed one.
2153 controller
.RemoveEntryAtIndex(0);
2154 EXPECT_EQ(3, controller
.GetEntryCount());
2155 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
2156 EXPECT_FALSE(controller
.GetPendingEntry());
2158 // Remove the 2 remaining entries.
2159 controller
.RemoveEntryAtIndex(1);
2160 controller
.RemoveEntryAtIndex(0);
2162 // This should leave us with only the last committed entry.
2163 EXPECT_EQ(1, controller
.GetEntryCount());
2164 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
2167 // Tests the transient entry, making sure it goes away with all navigations.
2168 TEST_F(NavigationControllerTest
, TransientEntry
) {
2169 NavigationControllerImpl
& controller
= controller_impl();
2170 TestNotificationTracker notifications
;
2171 RegisterForAllNavNotifications(¬ifications
, &controller
);
2173 const GURL
url0("http://foo/0");
2174 const GURL
url1("http://foo/1");
2175 const GURL
url2("http://foo/2");
2176 const GURL
url3("http://foo/3");
2177 const GURL
url3_ref("http://foo/3#bar");
2178 const GURL
url4("http://foo/4");
2179 const GURL
transient_url("http://foo/transient");
2182 url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2183 test_rvh()->SendNavigate(0, url0
);
2185 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2186 test_rvh()->SendNavigate(1, url1
);
2188 notifications
.Reset();
2190 // Adding a transient with no pending entry.
2191 NavigationEntryImpl
* transient_entry
= new NavigationEntryImpl
;
2192 transient_entry
->SetURL(transient_url
);
2193 controller
.AddTransientEntry(transient_entry
);
2195 // We should not have received any notifications.
2196 EXPECT_EQ(0U, notifications
.size());
2199 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2200 EXPECT_EQ(controller
.GetEntryCount(), 3);
2201 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 1);
2202 EXPECT_EQ(controller
.GetPendingEntryIndex(), -1);
2203 EXPECT_TRUE(controller
.GetLastCommittedEntry());
2204 EXPECT_FALSE(controller
.GetPendingEntry());
2205 EXPECT_TRUE(controller
.CanGoBack());
2206 EXPECT_FALSE(controller
.CanGoForward());
2207 EXPECT_EQ(contents()->GetMaxPageID(), 1);
2211 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2212 test_rvh()->SendNavigate(2, url2
);
2214 // We should have navigated, transient entry should be gone.
2215 EXPECT_EQ(url2
, controller
.GetActiveEntry()->GetURL());
2216 EXPECT_EQ(controller
.GetEntryCount(), 3);
2218 // Add a transient again, then navigate with no pending entry this time.
2219 transient_entry
= new NavigationEntryImpl
;
2220 transient_entry
->SetURL(transient_url
);
2221 controller
.AddTransientEntry(transient_entry
);
2222 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2223 test_rvh()->SendNavigate(3, url3
);
2224 // Transient entry should be gone.
2225 EXPECT_EQ(url3
, controller
.GetActiveEntry()->GetURL());
2226 EXPECT_EQ(controller
.GetEntryCount(), 4);
2228 // Initiate a navigation, add a transient then commit navigation.
2230 url4
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2231 transient_entry
= new NavigationEntryImpl
;
2232 transient_entry
->SetURL(transient_url
);
2233 controller
.AddTransientEntry(transient_entry
);
2234 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2235 test_rvh()->SendNavigate(4, url4
);
2236 EXPECT_EQ(url4
, controller
.GetActiveEntry()->GetURL());
2237 EXPECT_EQ(controller
.GetEntryCount(), 5);
2239 // Add a transient and go back. This should simply remove the transient.
2240 transient_entry
= new NavigationEntryImpl
;
2241 transient_entry
->SetURL(transient_url
);
2242 controller
.AddTransientEntry(transient_entry
);
2243 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2244 EXPECT_TRUE(controller
.CanGoBack());
2245 EXPECT_FALSE(controller
.CanGoForward());
2246 controller
.GoBack();
2247 // Transient entry should be gone.
2248 EXPECT_EQ(url4
, controller
.GetActiveEntry()->GetURL());
2249 EXPECT_EQ(controller
.GetEntryCount(), 5);
2250 test_rvh()->SendNavigate(3, url3
);
2252 // Add a transient and go to an entry before the current one.
2253 transient_entry
= new NavigationEntryImpl
;
2254 transient_entry
->SetURL(transient_url
);
2255 controller
.AddTransientEntry(transient_entry
);
2256 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2257 controller
.GoToIndex(1);
2258 // The navigation should have been initiated, transient entry should be gone.
2259 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
2260 // Visible entry does not update for history navigations until commit.
2261 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2262 test_rvh()->SendNavigate(1, url1
);
2263 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2265 // Add a transient and go to an entry after the current one.
2266 transient_entry
= new NavigationEntryImpl
;
2267 transient_entry
->SetURL(transient_url
);
2268 controller
.AddTransientEntry(transient_entry
);
2269 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2270 controller
.GoToIndex(3);
2271 // The navigation should have been initiated, transient entry should be gone.
2272 // Because of the transient entry that is removed, going to index 3 makes us
2273 // land on url2 (which is visible after the commit).
2274 EXPECT_EQ(url2
, controller
.GetActiveEntry()->GetURL());
2275 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2276 test_rvh()->SendNavigate(2, url2
);
2277 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2279 // Add a transient and go forward.
2280 transient_entry
= new NavigationEntryImpl
;
2281 transient_entry
->SetURL(transient_url
);
2282 controller
.AddTransientEntry(transient_entry
);
2283 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2284 EXPECT_TRUE(controller
.CanGoForward());
2285 controller
.GoForward();
2286 // We should have navigated, transient entry should be gone.
2287 EXPECT_EQ(url3
, controller
.GetActiveEntry()->GetURL());
2288 EXPECT_EQ(url2
, controller
.GetVisibleEntry()->GetURL());
2289 test_rvh()->SendNavigate(3, url3
);
2290 EXPECT_EQ(url3
, controller
.GetVisibleEntry()->GetURL());
2292 // Add a transient and do an in-page navigation, replacing the current entry.
2293 transient_entry
= new NavigationEntryImpl
;
2294 transient_entry
->SetURL(transient_url
);
2295 controller
.AddTransientEntry(transient_entry
);
2296 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2297 test_rvh()->SendNavigate(3, url3_ref
);
2298 // Transient entry should be gone.
2299 EXPECT_EQ(url3_ref
, controller
.GetActiveEntry()->GetURL());
2301 // Ensure the URLs are correct.
2302 EXPECT_EQ(controller
.GetEntryCount(), 5);
2303 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2304 EXPECT_EQ(controller
.GetEntryAtIndex(1)->GetURL(), url1
);
2305 EXPECT_EQ(controller
.GetEntryAtIndex(2)->GetURL(), url2
);
2306 EXPECT_EQ(controller
.GetEntryAtIndex(3)->GetURL(), url3_ref
);
2307 EXPECT_EQ(controller
.GetEntryAtIndex(4)->GetURL(), url4
);
2310 // Test that Reload initiates a new navigation to a transient entry's URL.
2311 TEST_F(NavigationControllerTest
, ReloadTransient
) {
2312 NavigationControllerImpl
& controller
= controller_impl();
2313 const GURL
url0("http://foo/0");
2314 const GURL
url1("http://foo/1");
2315 const GURL
transient_url("http://foo/transient");
2317 // Load |url0|, and start a pending navigation to |url1|.
2319 url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2320 test_rvh()->SendNavigate(0, url0
);
2322 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2324 // A transient entry is added, interrupting the navigation.
2325 NavigationEntryImpl
* transient_entry
= new NavigationEntryImpl
;
2326 transient_entry
->SetURL(transient_url
);
2327 controller
.AddTransientEntry(transient_entry
);
2328 EXPECT_TRUE(controller
.GetTransientEntry());
2329 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2331 // The page is reloaded, which should remove the pending entry for |url1| and
2332 // the transient entry for |transient_url|, and start a navigation to
2334 controller
.Reload(true);
2335 EXPECT_FALSE(controller
.GetTransientEntry());
2336 EXPECT_TRUE(controller
.GetPendingEntry());
2337 EXPECT_EQ(transient_url
, controller
.GetActiveEntry()->GetURL());
2338 ASSERT_EQ(controller
.GetEntryCount(), 1);
2339 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2341 // Load of |transient_url| completes.
2342 test_rvh()->SendNavigate(1, transient_url
);
2343 ASSERT_EQ(controller
.GetEntryCount(), 2);
2344 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url0
);
2345 EXPECT_EQ(controller
.GetEntryAtIndex(1)->GetURL(), transient_url
);
2348 // Tests that the URLs for renderer-initiated navigations are not displayed to
2349 // the user until the navigation commits, to prevent URL spoof attacks.
2350 // See http://crbug.com/99016.
2351 TEST_F(NavigationControllerTest
, DontShowRendererURLUntilCommit
) {
2352 NavigationControllerImpl
& controller
= controller_impl();
2353 TestNotificationTracker notifications
;
2354 RegisterForAllNavNotifications(¬ifications
, &controller
);
2356 const GURL
url0("http://foo/0");
2357 const GURL
url1("http://foo/1");
2359 // For typed navigations (browser-initiated), both active and visible entries
2360 // should update before commit.
2361 controller
.LoadURL(url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2362 EXPECT_EQ(url0
, controller
.GetActiveEntry()->GetURL());
2363 EXPECT_EQ(url0
, controller
.GetVisibleEntry()->GetURL());
2364 test_rvh()->SendNavigate(0, url0
);
2366 // For link clicks (renderer-initiated navigations), the active entry should
2367 // update before commit but the visible should not.
2368 NavigationController::LoadURLParams
load_url_params(url1
);
2369 load_url_params
.is_renderer_initiated
= true;
2370 controller
.LoadURLWithParams(load_url_params
);
2371 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
2372 EXPECT_EQ(url0
, controller
.GetVisibleEntry()->GetURL());
2374 NavigationEntryImpl::FromNavigationEntry(controller
.GetPendingEntry())->
2375 is_renderer_initiated());
2377 // After commit, both should be updated, and we should no longer treat the
2378 // entry as renderer-initiated.
2379 test_rvh()->SendNavigate(1, url1
);
2380 EXPECT_EQ(url1
, controller
.GetActiveEntry()->GetURL());
2381 EXPECT_EQ(url1
, controller
.GetVisibleEntry()->GetURL());
2383 NavigationEntryImpl::FromNavigationEntry(
2384 controller
.GetLastCommittedEntry())->is_renderer_initiated());
2386 notifications
.Reset();
2389 // Tests that IsInPageNavigation returns appropriate results. Prevents
2390 // regression for bug 1126349.
2391 TEST_F(NavigationControllerTest
, IsInPageNavigation
) {
2392 NavigationControllerImpl
& controller
= controller_impl();
2393 // Navigate to URL with no refs.
2394 const GURL
url("http://www.google.com/home.html");
2395 test_rvh()->SendNavigate(0, url
);
2397 // Reloading the page is not an in-page navigation.
2398 EXPECT_FALSE(controller
.IsURLInPageNavigation(url
));
2399 const GURL
other_url("http://www.google.com/add.html");
2400 EXPECT_FALSE(controller
.IsURLInPageNavigation(other_url
));
2401 const GURL
url_with_ref("http://www.google.com/home.html#my_ref");
2402 EXPECT_TRUE(controller
.IsURLInPageNavigation(url_with_ref
));
2404 // Navigate to URL with refs.
2405 test_rvh()->SendNavigate(1, url_with_ref
);
2407 // Reloading the page is not an in-page navigation.
2408 EXPECT_FALSE(controller
.IsURLInPageNavigation(url_with_ref
));
2409 EXPECT_FALSE(controller
.IsURLInPageNavigation(url
));
2410 EXPECT_FALSE(controller
.IsURLInPageNavigation(other_url
));
2411 const GURL
other_url_with_ref("http://www.google.com/home.html#my_other_ref");
2412 EXPECT_TRUE(controller
.IsURLInPageNavigation(
2413 other_url_with_ref
));
2416 // Some pages can have subframes with the same base URL (minus the reference) as
2417 // the main page. Even though this is hard, it can happen, and we don't want
2418 // these subframe navigations to affect the toplevel document. They should
2419 // instead be ignored. http://crbug.com/5585
2420 TEST_F(NavigationControllerTest
, SameSubframe
) {
2421 NavigationControllerImpl
& controller
= controller_impl();
2422 // Navigate the main frame.
2423 const GURL
url("http://www.google.com/");
2424 test_rvh()->SendNavigate(0, url
);
2426 // We should be at the first navigation entry.
2427 EXPECT_EQ(controller
.GetEntryCount(), 1);
2428 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
2430 // Navigate a subframe that would normally count as in-page.
2431 const GURL
subframe("http://www.google.com/#");
2432 ViewHostMsg_FrameNavigate_Params params
;
2434 params
.url
= subframe
;
2435 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
2436 params
.should_update_history
= false;
2437 params
.gesture
= NavigationGestureAuto
;
2438 params
.is_post
= false;
2439 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(subframe
));
2440 LoadCommittedDetails details
;
2441 EXPECT_FALSE(controller
.RendererDidNavigate(params
, &details
));
2443 // Nothing should have changed.
2444 EXPECT_EQ(controller
.GetEntryCount(), 1);
2445 EXPECT_EQ(controller
.GetLastCommittedEntryIndex(), 0);
2448 // Make sure that on cloning a WebContentsImpl and going back needs_reload is
2450 TEST_F(NavigationControllerTest
, CloneAndGoBack
) {
2451 NavigationControllerImpl
& controller
= controller_impl();
2452 const GURL
url1("http://foo1");
2453 const GURL
url2("http://foo2");
2455 NavigateAndCommit(url1
);
2456 NavigateAndCommit(url2
);
2458 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
2460 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
2461 EXPECT_TRUE(clone
->GetController().NeedsReload());
2462 clone
->GetController().GoBack();
2463 // Navigating back should have triggered needs_reload_ to go false.
2464 EXPECT_FALSE(clone
->GetController().NeedsReload());
2467 // Make sure that cloning a WebContentsImpl doesn't copy interstitials.
2468 TEST_F(NavigationControllerTest
, CloneOmitsInterstitials
) {
2469 NavigationControllerImpl
& controller
= controller_impl();
2470 const GURL
url1("http://foo1");
2471 const GURL
url2("http://foo2");
2473 NavigateAndCommit(url1
);
2474 NavigateAndCommit(url2
);
2476 // Add an interstitial entry. Should be deleted with controller.
2477 NavigationEntryImpl
* interstitial_entry
= new NavigationEntryImpl();
2478 interstitial_entry
->set_page_type(PAGE_TYPE_INTERSTITIAL
);
2479 controller
.AddTransientEntry(interstitial_entry
);
2481 scoped_ptr
<WebContents
> clone(controller
.GetWebContents()->Clone());
2483 ASSERT_EQ(2, clone
->GetController().GetEntryCount());
2486 // Tests a subframe navigation while a toplevel navigation is pending.
2487 // http://crbug.com/43967
2488 TEST_F(NavigationControllerTest
, SubframeWhilePending
) {
2489 NavigationControllerImpl
& controller
= controller_impl();
2490 // Load the first page.
2491 const GURL
url1("http://foo/");
2492 NavigateAndCommit(url1
);
2494 // Now start a pending load to a totally different page, but don't commit it.
2495 const GURL
url2("http://bar/");
2497 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2499 // Send a subframe update from the first page, as if one had just
2500 // automatically loaded. Auto subframes don't increment the page ID.
2501 const GURL
url1_sub("http://foo/subframe");
2502 ViewHostMsg_FrameNavigate_Params params
;
2503 params
.page_id
= controller
.GetLastCommittedEntry()->GetPageID();
2504 params
.url
= url1_sub
;
2505 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
2506 params
.should_update_history
= false;
2507 params
.gesture
= NavigationGestureAuto
;
2508 params
.is_post
= false;
2509 params
.content_state
= webkit_glue::CreateHistoryStateForURL(GURL(url1_sub
));
2510 LoadCommittedDetails details
;
2512 // This should return false meaning that nothing was actually updated.
2513 EXPECT_FALSE(controller
.RendererDidNavigate(params
, &details
));
2515 // The notification should have updated the last committed one, and not
2516 // the pending load.
2517 EXPECT_EQ(url1
, controller
.GetLastCommittedEntry()->GetURL());
2519 // The active entry should be unchanged by the subframe load.
2520 EXPECT_EQ(url2
, controller
.GetActiveEntry()->GetURL());
2523 // Test CopyStateFrom with 2 urls, the first selected and nothing in the target.
2524 TEST_F(NavigationControllerTest
, CopyStateFrom
) {
2525 NavigationControllerImpl
& controller
= controller_impl();
2526 const GURL
url1("http://foo1");
2527 const GURL
url2("http://foo2");
2529 NavigateAndCommit(url1
);
2530 NavigateAndCommit(url2
);
2531 controller
.GoBack();
2532 contents()->CommitPendingNavigation();
2534 scoped_ptr
<TestWebContents
> other_contents(
2535 static_cast<TestWebContents
*>(CreateTestWebContents()));
2536 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2537 other_controller
.CopyStateFrom(controller
);
2539 // other_controller should now contain 2 urls.
2540 ASSERT_EQ(2, other_controller
.GetEntryCount());
2541 // We should be looking at the first one.
2542 ASSERT_EQ(0, other_controller
.GetCurrentEntryIndex());
2544 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2545 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
2546 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
2547 // This is a different site than url1, so the IDs start again at 0.
2548 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(1)->GetPageID());
2550 // The max page ID map should be copied over and updated with the max page ID
2551 // from the current tab.
2552 SiteInstance
* instance1
=
2553 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0));
2554 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
2556 // Ensure the SessionStorageNamespaceMaps are the same size and have
2557 // the same partitons loaded.
2559 // TODO(ajwong): We should load a url from a different partition earlier
2560 // to make sure this map has more than one entry.
2561 const SessionStorageNamespaceMap
& session_storage_namespace_map
=
2562 controller
.GetSessionStorageNamespaceMap();
2563 const SessionStorageNamespaceMap
& other_session_storage_namespace_map
=
2564 other_controller
.GetSessionStorageNamespaceMap();
2565 EXPECT_EQ(session_storage_namespace_map
.size(),
2566 other_session_storage_namespace_map
.size());
2567 for (SessionStorageNamespaceMap::const_iterator it
=
2568 session_storage_namespace_map
.begin();
2569 it
!= session_storage_namespace_map
.end();
2571 SessionStorageNamespaceMap::const_iterator other
=
2572 other_session_storage_namespace_map
.find(it
->first
);
2573 EXPECT_TRUE(other
!= other_session_storage_namespace_map
.end());
2577 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
2578 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune
) {
2579 NavigationControllerImpl
& controller
= controller_impl();
2580 const GURL
url1("http://foo/1");
2581 const GURL
url2("http://foo/2");
2582 const GURL
url3("http://foo/3");
2584 NavigateAndCommit(url1
);
2585 NavigateAndCommit(url2
);
2587 // First two entries should have the same SiteInstance.
2588 SiteInstance
* instance1
=
2589 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(0));
2590 SiteInstance
* instance2
=
2591 GetSiteInstanceFromEntry(controller
.GetEntryAtIndex(1));
2592 EXPECT_EQ(instance1
, instance2
);
2593 EXPECT_EQ(0, controller
.GetEntryAtIndex(0)->GetPageID());
2594 EXPECT_EQ(1, controller
.GetEntryAtIndex(1)->GetPageID());
2595 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1
));
2597 scoped_ptr
<TestWebContents
> other_contents(
2598 static_cast<TestWebContents
*>(CreateTestWebContents()));
2599 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2600 other_contents
->NavigateAndCommit(url3
);
2601 other_contents
->ExpectSetHistoryLengthAndPrune(
2602 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
2603 other_controller
.GetEntryAtIndex(0)->GetPageID());
2604 other_controller
.CopyStateFromAndPrune(&controller
);
2606 // other_controller should now contain the 3 urls: url1, url2 and url3.
2608 ASSERT_EQ(3, other_controller
.GetEntryCount());
2610 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
2612 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2613 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(1)->GetURL());
2614 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(2)->GetURL());
2615 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
2616 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(1)->GetPageID());
2617 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
2619 // A new SiteInstance should be used for the new tab.
2620 SiteInstance
* instance3
=
2621 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(2));
2622 EXPECT_NE(instance3
, instance1
);
2624 // The max page ID map should be copied over and updated with the max page ID
2625 // from the current tab.
2626 EXPECT_EQ(1, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
2627 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance3
));
2630 // Test CopyStateFromAndPrune with 2 urls, the first selected and nothing in
2632 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune2
) {
2633 NavigationControllerImpl
& controller
= controller_impl();
2634 const GURL
url1("http://foo1");
2635 const GURL
url2("http://foo2");
2636 const GURL
url3("http://foo3");
2638 NavigateAndCommit(url1
);
2639 NavigateAndCommit(url2
);
2640 controller
.GoBack();
2642 scoped_ptr
<TestWebContents
> other_contents(
2643 static_cast<TestWebContents
*>(CreateTestWebContents()));
2644 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2645 other_contents
->ExpectSetHistoryLengthAndPrune(NULL
, 1, -1);
2646 other_controller
.CopyStateFromAndPrune(&controller
);
2648 // other_controller should now contain the 1 url: url1.
2650 ASSERT_EQ(1, other_controller
.GetEntryCount());
2652 ASSERT_EQ(0, other_controller
.GetCurrentEntryIndex());
2654 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2655 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(0)->GetPageID());
2657 // The max page ID map should be copied over and updated with the max page ID
2658 // from the current tab.
2659 SiteInstance
* instance1
=
2660 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0));
2661 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
2664 // Test CopyStateFromAndPrune with 2 urls, the first selected and nothing in
2666 TEST_F(NavigationControllerTest
, CopyStateFromAndPrune3
) {
2667 NavigationControllerImpl
& controller
= controller_impl();
2668 const GURL
url1("http://foo1");
2669 const GURL
url2("http://foo2");
2670 const GURL
url3("http://foo3");
2672 NavigateAndCommit(url1
);
2673 NavigateAndCommit(url2
);
2674 controller
.GoBack();
2676 scoped_ptr
<TestWebContents
> other_contents(
2677 static_cast<TestWebContents
*>(CreateTestWebContents()));
2678 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2679 other_controller
.LoadURL(
2680 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2681 other_contents
->ExpectSetHistoryLengthAndPrune(NULL
, 1, -1);
2682 other_controller
.CopyStateFromAndPrune(&controller
);
2684 // other_controller should now contain 1 entry for url1, and a pending entry
2687 ASSERT_EQ(1, other_controller
.GetEntryCount());
2689 EXPECT_EQ(0, other_controller
.GetCurrentEntryIndex());
2691 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2693 // And there should be a pending entry for url3.
2694 ASSERT_TRUE(other_controller
.GetPendingEntry());
2696 EXPECT_EQ(url3
, other_controller
.GetPendingEntry()->GetURL());
2698 // The max page ID map should be copied over and updated with the max page ID
2699 // from the current tab.
2700 SiteInstance
* instance1
=
2701 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0));
2702 EXPECT_EQ(0, other_contents
->GetMaxPageIDForSiteInstance(instance1
));
2705 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest,
2706 // when the max entry count is 3. We should prune one entry.
2707 TEST_F(NavigationControllerTest
, CopyStateFromAndPruneMaxEntries
) {
2708 NavigationControllerImpl
& controller
= controller_impl();
2709 size_t original_count
= NavigationControllerImpl::max_entry_count();
2710 const int kMaxEntryCount
= 3;
2712 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount
);
2714 const GURL
url1("http://foo/1");
2715 const GURL
url2("http://foo/2");
2716 const GURL
url3("http://foo/3");
2717 const GURL
url4("http://foo/4");
2719 // Create a PrunedListener to observe prune notifications.
2720 PrunedListener
listener(&controller
);
2722 NavigateAndCommit(url1
);
2723 NavigateAndCommit(url2
);
2724 NavigateAndCommit(url3
);
2726 scoped_ptr
<TestWebContents
> other_contents(
2727 static_cast<TestWebContents
*>(CreateTestWebContents()));
2728 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2729 other_contents
->NavigateAndCommit(url4
);
2730 other_contents
->ExpectSetHistoryLengthAndPrune(
2731 GetSiteInstanceFromEntry(other_controller
.GetEntryAtIndex(0)), 2,
2732 other_controller
.GetEntryAtIndex(0)->GetPageID());
2733 other_controller
.CopyStateFromAndPrune(&controller
);
2735 // We should have received a pruned notification.
2736 EXPECT_EQ(1, listener
.notification_count_
);
2737 EXPECT_TRUE(listener
.details_
.from_front
);
2738 EXPECT_EQ(1, listener
.details_
.count
);
2740 // other_controller should now contain only 3 urls: url2, url3 and url4.
2742 ASSERT_EQ(3, other_controller
.GetEntryCount());
2744 ASSERT_EQ(2, other_controller
.GetCurrentEntryIndex());
2746 EXPECT_EQ(url2
, other_controller
.GetEntryAtIndex(0)->GetURL());
2747 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2748 EXPECT_EQ(url4
, other_controller
.GetEntryAtIndex(2)->GetURL());
2749 EXPECT_EQ(1, other_controller
.GetEntryAtIndex(0)->GetPageID());
2750 EXPECT_EQ(2, other_controller
.GetEntryAtIndex(1)->GetPageID());
2751 EXPECT_EQ(0, other_controller
.GetEntryAtIndex(2)->GetPageID());
2753 NavigationControllerImpl::set_max_entry_count_for_testing(original_count
);
2756 // Tests that navigations initiated from the page (with the history object)
2757 // work as expected without navigation entries.
2758 TEST_F(NavigationControllerTest
, HistoryNavigate
) {
2759 NavigationControllerImpl
& controller
= controller_impl();
2760 const GURL
url1("http://foo/1");
2761 const GURL
url2("http://foo/2");
2762 const GURL
url3("http://foo/3");
2764 NavigateAndCommit(url1
);
2765 NavigateAndCommit(url2
);
2766 NavigateAndCommit(url3
);
2767 controller
.GoBack();
2768 contents()->CommitPendingNavigation();
2770 // Simulate the page calling history.back(), it should not create a pending
2772 contents()->OnGoToEntryAtOffset(-1);
2773 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
2774 // The actual cross-navigation is suspended until the current RVH tells us
2775 // it unloaded, simulate that.
2776 contents()->ProceedWithCrossSiteNavigation();
2777 // Also make sure we told the page to navigate.
2778 const IPC::Message
* message
=
2779 process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID
);
2780 ASSERT_TRUE(message
!= NULL
);
2781 Tuple1
<ViewMsg_Navigate_Params
> nav_params
;
2782 ViewMsg_Navigate::Read(message
, &nav_params
);
2783 EXPECT_EQ(url1
, nav_params
.a
.url
);
2784 process()->sink().ClearMessages();
2786 // Now test history.forward()
2787 contents()->OnGoToEntryAtOffset(1);
2788 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
2789 // The actual cross-navigation is suspended until the current RVH tells us
2790 // it unloaded, simulate that.
2791 contents()->ProceedWithCrossSiteNavigation();
2792 message
= process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID
);
2793 ASSERT_TRUE(message
!= NULL
);
2794 ViewMsg_Navigate::Read(message
, &nav_params
);
2795 EXPECT_EQ(url3
, nav_params
.a
.url
);
2796 process()->sink().ClearMessages();
2798 // Make sure an extravagant history.go() doesn't break.
2799 contents()->OnGoToEntryAtOffset(120); // Out of bounds.
2800 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
2801 message
= process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID
);
2802 EXPECT_TRUE(message
== NULL
);
2805 // Test call to PruneAllButActive for the only entry.
2806 TEST_F(NavigationControllerTest
, PruneAllButActiveForSingle
) {
2807 NavigationControllerImpl
& controller
= controller_impl();
2808 const GURL
url1("http://foo1");
2809 NavigateAndCommit(url1
);
2810 controller
.PruneAllButActive();
2812 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
2813 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url1
);
2816 // Test call to PruneAllButActive for last entry.
2817 TEST_F(NavigationControllerTest
, PruneAllButActiveForLast
) {
2818 NavigationControllerImpl
& controller
= controller_impl();
2819 const GURL
url1("http://foo/1");
2820 const GURL
url2("http://foo/2");
2821 const GURL
url3("http://foo/3");
2823 NavigateAndCommit(url1
);
2824 NavigateAndCommit(url2
);
2825 NavigateAndCommit(url3
);
2826 controller
.GoBack();
2827 controller
.GoBack();
2828 contents()->CommitPendingNavigation();
2830 controller
.PruneAllButActive();
2832 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
2833 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url1
);
2836 // Test call to PruneAllButActive for intermediate entry.
2837 TEST_F(NavigationControllerTest
, PruneAllButActiveForIntermediate
) {
2838 NavigationControllerImpl
& controller
= controller_impl();
2839 const GURL
url1("http://foo/1");
2840 const GURL
url2("http://foo/2");
2841 const GURL
url3("http://foo/3");
2843 NavigateAndCommit(url1
);
2844 NavigateAndCommit(url2
);
2845 NavigateAndCommit(url3
);
2846 controller
.GoBack();
2847 contents()->CommitPendingNavigation();
2849 controller
.PruneAllButActive();
2851 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
2852 EXPECT_EQ(controller
.GetEntryAtIndex(0)->GetURL(), url2
);
2855 // Test call to PruneAllButActive for intermediate entry.
2856 TEST_F(NavigationControllerTest
, PruneAllButActiveForPending
) {
2857 NavigationControllerImpl
& controller
= controller_impl();
2858 const GURL
url1("http://foo/1");
2859 const GURL
url2("http://foo/2");
2860 const GURL
url3("http://foo/3");
2862 NavigateAndCommit(url1
);
2863 NavigateAndCommit(url2
);
2864 NavigateAndCommit(url3
);
2865 controller
.GoBack();
2867 controller
.PruneAllButActive();
2869 EXPECT_EQ(0, controller
.GetPendingEntryIndex());
2872 // Test call to PruneAllButActive for transient entry.
2873 TEST_F(NavigationControllerTest
, PruneAllButActiveForTransient
) {
2874 NavigationControllerImpl
& controller
= controller_impl();
2875 const GURL
url0("http://foo/0");
2876 const GURL
url1("http://foo/1");
2877 const GURL
transient_url("http://foo/transient");
2880 url0
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2881 test_rvh()->SendNavigate(0, url0
);
2883 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2884 test_rvh()->SendNavigate(1, url1
);
2886 // Adding a transient with no pending entry.
2887 NavigationEntryImpl
* transient_entry
= new NavigationEntryImpl
;
2888 transient_entry
->SetURL(transient_url
);
2889 controller
.AddTransientEntry(transient_entry
);
2891 controller
.PruneAllButActive();
2893 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
2894 EXPECT_EQ(controller
.GetTransientEntry()->GetURL(), transient_url
);
2897 // Test to ensure that when we do a history navigation back to the current
2898 // committed page (e.g., going forward to a slow-loading page, then pressing
2899 // the back button), we just stop the navigation to prevent the throbber from
2900 // running continuously. Otherwise, the RenderViewHost forces the throbber to
2901 // start, but WebKit essentially ignores the navigation and never sends a
2902 // message to stop the throbber.
2903 TEST_F(NavigationControllerTest
, StopOnHistoryNavigationToCurrentPage
) {
2904 NavigationControllerImpl
& controller
= controller_impl();
2905 const GURL
url0("http://foo/0");
2906 const GURL
url1("http://foo/1");
2908 NavigateAndCommit(url0
);
2909 NavigateAndCommit(url1
);
2911 // Go back to the original page, then forward to the slow page, then back
2912 controller
.GoBack();
2913 contents()->CommitPendingNavigation();
2915 controller
.GoForward();
2916 EXPECT_EQ(1, controller
.GetPendingEntryIndex());
2918 controller
.GoBack();
2919 EXPECT_EQ(-1, controller
.GetPendingEntryIndex());
2922 TEST_F(NavigationControllerTest
, IsInitialNavigation
) {
2923 NavigationControllerImpl
& controller
= controller_impl();
2924 TestNotificationTracker notifications
;
2925 RegisterForAllNavNotifications(¬ifications
, &controller
);
2928 EXPECT_TRUE(controller
.IsInitialNavigation());
2930 // After load, it is false.
2931 controller
.DocumentLoadedInFrame();
2932 EXPECT_FALSE(controller
.IsInitialNavigation());
2934 const GURL
url1("http://foo1");
2935 test_rvh()->SendNavigate(0, url1
);
2936 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
2938 // After commit, it stays false.
2939 EXPECT_FALSE(controller
.IsInitialNavigation());
2942 // Check that the favicon is not reused across a client redirect.
2943 // (crbug.com/28515)
2944 TEST_F(NavigationControllerTest
, ClearFaviconOnRedirect
) {
2945 const GURL
kPageWithFavicon("http://withfavicon.html");
2946 const GURL
kPageWithoutFavicon("http://withoutfavicon.html");
2947 const GURL
kIconURL("http://withfavicon.ico");
2948 const gfx::Image kDefaultFavicon
= FaviconStatus().image
;
2950 NavigationControllerImpl
& controller
= controller_impl();
2951 TestNotificationTracker notifications
;
2952 RegisterForAllNavNotifications(¬ifications
, &controller
);
2954 test_rvh()->SendNavigate(0, kPageWithFavicon
);
2955 EXPECT_TRUE(notifications
.Check1AndReset(
2956 NOTIFICATION_NAV_ENTRY_COMMITTED
));
2958 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
2960 EXPECT_EQ(kPageWithFavicon
, entry
->GetURL());
2962 // Simulate Chromium having set the favicon for |kPageWithFavicon|.
2963 content::FaviconStatus
& favicon_status
= entry
->GetFavicon();
2964 favicon_status
.image
= CreateImage(SK_ColorWHITE
);
2965 favicon_status
.url
= kIconURL
;
2966 favicon_status
.valid
= true;
2967 EXPECT_FALSE(DoImagesMatch(kDefaultFavicon
, entry
->GetFavicon().image
));
2969 test_rvh()->SendNavigateWithTransition(
2971 kPageWithoutFavicon
,
2972 PAGE_TRANSITION_CLIENT_REDIRECT
);
2973 EXPECT_TRUE(notifications
.Check1AndReset(
2974 NOTIFICATION_NAV_ENTRY_COMMITTED
));
2976 entry
= controller
.GetLastCommittedEntry();
2978 EXPECT_EQ(kPageWithoutFavicon
, entry
->GetURL());
2980 EXPECT_TRUE(DoImagesMatch(kDefaultFavicon
, entry
->GetFavicon().image
));
2983 // Check that the favicon is not cleared for NavigationEntries which were
2984 // previously navigated to.
2985 TEST_F(NavigationControllerTest
, BackNavigationDoesNotClearFavicon
) {
2986 const GURL
kUrl1("http://www.a.com/1");
2987 const GURL
kUrl2("http://www.a.com/2");
2988 const GURL
kIconURL("http://www.a.com/1/favicon.ico");
2990 NavigationControllerImpl
& controller
= controller_impl();
2991 TestNotificationTracker notifications
;
2992 RegisterForAllNavNotifications(¬ifications
, &controller
);
2994 test_rvh()->SendNavigate(0, kUrl1
);
2995 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
2997 // Simulate Chromium having set the favicon for |kUrl1|.
2998 gfx::Image favicon_image
= CreateImage(SK_ColorWHITE
);
2999 content::NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
3001 content::FaviconStatus
& favicon_status
= entry
->GetFavicon();
3002 favicon_status
.image
= favicon_image
;
3003 favicon_status
.url
= kIconURL
;
3004 favicon_status
.valid
= true;
3006 // Navigate to another page and go back to the original page.
3007 test_rvh()->SendNavigate(1, kUrl2
);
3008 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
3009 test_rvh()->SendNavigateWithTransition(
3012 PAGE_TRANSITION_FORWARD_BACK
);
3013 EXPECT_TRUE(notifications
.Check1AndReset(NOTIFICATION_NAV_ENTRY_COMMITTED
));
3015 // Verify that the favicon for the page at |kUrl1| was not cleared.
3016 entry
= controller
.GetEntryAtIndex(0);
3018 EXPECT_EQ(kUrl1
, entry
->GetURL());
3019 EXPECT_TRUE(DoImagesMatch(favicon_image
, entry
->GetFavicon().image
));
3022 // The test crashes on android: http://crbug.com/170449
3023 #if defined(OS_ANDROID)
3024 #define MAYBE_PurgeScreenshot DISABLED_PurgeScreenshot
3026 #define MAYBE_PurgeScreenshot PurgeScreenshot
3028 // Tests that screenshot are purged correctly.
3029 TEST_F(NavigationControllerTest
, MAYBE_PurgeScreenshot
) {
3030 NavigationControllerImpl
& controller
= controller_impl();
3032 // Prepare some data to use as screenshot for each navigation.
3033 skia::PlatformBitmap bitmap
;
3034 ASSERT_TRUE(bitmap
.Allocate(1, 1, false));
3035 NavigationEntryImpl
* entry
;
3037 // Navigate enough times to make sure that some screenshots are purged.
3038 for (int i
= 0; i
< 12; ++i
) {
3039 const GURL
url(base::StringPrintf("http://foo%d/", i
));
3040 NavigateAndCommit(url
);
3041 EXPECT_EQ(i
, controller
.GetCurrentEntryIndex());
3044 for (int i
= 0; i
< controller
.GetEntryCount(); ++i
) {
3045 entry
= NavigationEntryImpl::FromNavigationEntry(
3046 controller
.GetEntryAtIndex(i
));
3047 controller
.OnScreenshotTaken(entry
->GetUniqueID(), &bitmap
, true);
3048 EXPECT_TRUE(entry
->screenshot());
3051 NavigateAndCommit(GURL("https://foo/"));
3052 EXPECT_EQ(13, controller
.GetEntryCount());
3053 entry
= NavigationEntryImpl::FromNavigationEntry(
3054 controller
.GetEntryAtIndex(11));
3055 controller
.OnScreenshotTaken(entry
->GetUniqueID(), &bitmap
, true);
3057 for (int i
= 0; i
< 2; ++i
) {
3058 entry
= NavigationEntryImpl::FromNavigationEntry(
3059 controller
.GetEntryAtIndex(i
));
3060 EXPECT_FALSE(entry
->screenshot()) << "Screenshot " << i
<< " not purged";
3063 for (int i
= 2; i
< controller
.GetEntryCount() - 1; ++i
) {
3064 entry
= NavigationEntryImpl::FromNavigationEntry(
3065 controller
.GetEntryAtIndex(i
));
3066 EXPECT_TRUE(entry
->screenshot()) << "Screenshot not found for " << i
;
3069 // Navigate to index 5 and then try to assign screenshot to all entries.
3070 controller
.GoToIndex(5);
3071 contents()->CommitPendingNavigation();
3072 EXPECT_EQ(5, controller
.GetCurrentEntryIndex());
3073 for (int i
= 0; i
< controller
.GetEntryCount() - 1; ++i
) {
3074 entry
= NavigationEntryImpl::FromNavigationEntry(
3075 controller
.GetEntryAtIndex(i
));
3076 controller
.OnScreenshotTaken(entry
->GetUniqueID(), &bitmap
, true);
3079 for (int i
= 10; i
<= 12; ++i
) {
3080 entry
= NavigationEntryImpl::FromNavigationEntry(
3081 controller
.GetEntryAtIndex(i
));
3082 EXPECT_FALSE(entry
->screenshot()) << "Screenshot " << i
<< " not purged";
3083 controller
.OnScreenshotTaken(entry
->GetUniqueID(), &bitmap
, true);
3086 // Navigate to index 7 and assign screenshot to all entries.
3087 controller
.GoToIndex(7);
3088 contents()->CommitPendingNavigation();
3089 EXPECT_EQ(7, controller
.GetCurrentEntryIndex());
3090 for (int i
= 0; i
< controller
.GetEntryCount() - 1; ++i
) {
3091 entry
= NavigationEntryImpl::FromNavigationEntry(
3092 controller
.GetEntryAtIndex(i
));
3093 controller
.OnScreenshotTaken(entry
->GetUniqueID(), &bitmap
, true);
3096 for (int i
= 0; i
< 2; ++i
) {
3097 entry
= NavigationEntryImpl::FromNavigationEntry(
3098 controller
.GetEntryAtIndex(i
));
3099 EXPECT_FALSE(entry
->screenshot()) << "Screenshot " << i
<< " not purged";
3102 // Clear all screenshots.
3103 EXPECT_EQ(13, controller
.GetEntryCount());
3104 EXPECT_EQ(10, controller
.screenshot_count_
);
3105 controller
.ClearAllScreenshots();
3106 EXPECT_EQ(0, controller
.screenshot_count_
);
3107 for (int i
= 0; i
< controller
.GetEntryCount(); ++i
) {
3108 entry
= NavigationEntryImpl::FromNavigationEntry(
3109 controller
.GetEntryAtIndex(i
));
3110 EXPECT_FALSE(entry
->screenshot()) << "Screenshot " << i
<< " not cleared";
3114 /* TODO(brettw) These test pass on my local machine but fail on the XP buildbot
3115 (but not Vista) cleaning up the directory after they run.
3116 This should be fixed.
3118 // NavigationControllerHistoryTest ---------------------------------------------
3120 class NavigationControllerHistoryTest : public NavigationControllerTest {
3122 NavigationControllerHistoryTest()
3123 : url0("http://foo1"),
3124 url1("http://foo1"),
3125 url2("http://foo1"),
3126 profile_manager_(NULL) {
3129 virtual ~NavigationControllerHistoryTest() {
3130 // Prevent our base class from deleting the profile since profile's
3131 // lifetime is managed by profile_manager_.
3132 STLDeleteElements(&windows_);
3135 // testing::Test overrides.
3136 virtual void SetUp() {
3137 NavigationControllerTest::SetUp();
3139 // Force the session service to be created.
3140 SessionService* service = new SessionService(profile());
3141 SessionServiceFactory::SetForTestProfile(profile(), service);
3142 service->SetWindowType(window_id, Browser::TYPE_TABBED);
3143 service->SetWindowBounds(window_id, gfx::Rect(0, 1, 2, 3), false);
3144 service->SetTabIndexInWindow(window_id,
3145 controller.session_id(), 0);
3146 controller.SetWindowID(window_id);
3148 session_helper_.set_service(service);
3151 virtual void TearDown() {
3152 // Release profile's reference to the session service. Otherwise the file
3153 // will still be open and we won't be able to delete the directory below.
3154 session_helper_.ReleaseService(); // profile owns this
3155 SessionServiceFactory::SetForTestProfile(profile(), NULL);
3157 // Make sure we wait for history to shut down before continuing. The task
3158 // we add will cause our message loop to quit once it is destroyed.
3159 HistoryService* history = HistoryServiceFactory::GetForProfiles(
3160 profile(), Profile::IMPLICIT_ACCESS);
3162 history->SetOnBackendDestroyTask(MessageLoop::QuitClosure());
3163 MessageLoop::current()->Run();
3166 // Do normal cleanup before deleting the profile directory below.
3167 NavigationControllerTest::TearDown();
3169 ASSERT_TRUE(file_util::Delete(test_dir_, true));
3170 ASSERT_FALSE(file_util::PathExists(test_dir_));
3173 // Deletes the current profile manager and creates a new one. Indirectly this
3174 // shuts down the history database and reopens it.
3175 void ReopenDatabase() {
3176 session_helper_.set_service(NULL);
3177 SessionServiceFactory::SetForTestProfile(profile(), NULL);
3179 SessionService* service = new SessionService(profile());
3180 SessionServiceFactory::SetForTestProfile(profile(), service);
3181 session_helper_.set_service(service);
3184 void GetLastSession() {
3185 SessionServiceFactory::GetForProfile(profile())->TabClosed(
3186 controller.window_id(), controller.session_id(), false);
3191 session_helper_.ReadWindows(&windows_);
3194 CancelableRequestConsumer consumer;
3196 // URLs for testing.
3201 std::vector<SessionWindow*> windows_;
3203 SessionID window_id;
3205 SessionServiceTestHelper session_helper_;
3208 ProfileManager* profile_manager_;
3212 // A basic test case. Navigates to a single url, and make sure the history
3214 TEST_F(NavigationControllerHistoryTest, Basic) {
3215 NavigationControllerImpl& controller = controller_impl();
3216 controller.LoadURL(url0, GURL(), PAGE_TRANSITION_LINK);
3217 test_rvh()->SendNavigate(0, url0);
3221 session_helper_.AssertSingleWindowWithSingleTab(windows_, 1);
3222 session_helper_.AssertTabEquals(0, 0, 1, *(windows_[0]->tabs[0]));
3223 TabNavigation nav1(0, url0, GURL(), string16(),
3224 webkit_glue::CreateHistoryStateForURL(url0),
3225 PAGE_TRANSITION_LINK);
3226 session_helper_.AssertNavigationEquals(nav1,
3227 windows_[0]->tabs[0]->navigations[0]);
3230 // Navigates to three urls, then goes back and make sure the history database
3232 TEST_F(NavigationControllerHistoryTest, NavigationThenBack) {
3233 NavigationControllerImpl& controller = controller_impl();
3234 test_rvh()->SendNavigate(0, url0);
3235 test_rvh()->SendNavigate(1, url1);
3236 test_rvh()->SendNavigate(2, url2);
3238 controller.GoBack();
3239 test_rvh()->SendNavigate(1, url1);
3243 session_helper_.AssertSingleWindowWithSingleTab(windows_, 3);
3244 session_helper_.AssertTabEquals(0, 1, 3, *(windows_[0]->tabs[0]));
3246 TabNavigation nav(0, url0, GURL(), string16(),
3247 webkit_glue::CreateHistoryStateForURL(url0),
3248 PAGE_TRANSITION_LINK);
3249 session_helper_.AssertNavigationEquals(nav,
3250 windows_[0]->tabs[0]->navigations[0]);
3252 session_helper_.AssertNavigationEquals(nav,
3253 windows_[0]->tabs[0]->navigations[1]);
3255 session_helper_.AssertNavigationEquals(nav,
3256 windows_[0]->tabs[0]->navigations[2]);
3259 // Navigates to three urls, then goes back twice, then loads a new url.
3260 TEST_F(NavigationControllerHistoryTest, NavigationPruning) {
3261 NavigationControllerImpl& controller = controller_impl();
3262 test_rvh()->SendNavigate(0, url0);
3263 test_rvh()->SendNavigate(1, url1);
3264 test_rvh()->SendNavigate(2, url2);
3266 controller.GoBack();
3267 test_rvh()->SendNavigate(1, url1);
3269 controller.GoBack();
3270 test_rvh()->SendNavigate(0, url0);
3272 test_rvh()->SendNavigate(3, url2);
3274 // Now have url0, and url2.
3278 session_helper_.AssertSingleWindowWithSingleTab(windows_, 2);
3279 session_helper_.AssertTabEquals(0, 1, 2, *(windows_[0]->tabs[0]));
3281 TabNavigation nav(0, url0, GURL(), string16(),
3282 webkit_glue::CreateHistoryStateForURL(url0),
3283 PAGE_TRANSITION_LINK);
3284 session_helper_.AssertNavigationEquals(nav,
3285 windows_[0]->tabs[0]->navigations[0]);
3287 session_helper_.AssertNavigationEquals(nav,
3288 windows_[0]->tabs[0]->navigations[1]);
3292 } // namespace content