Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / content / browser / frame_host / navigation_controller_impl_unittest.cc
blob1a8c8a9b0de32ff3710d9bbb2c43c6b8b08a1c47
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/basictypes.h"
6 #include "base/bind.h"
7 #include "base/file_util.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/path_service.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h"
14 #include "content/browser/frame_host/cross_site_transferring_request.h"
15 #include "content/browser/frame_host/navigation_controller_impl.h"
16 #include "content/browser/frame_host/navigation_entry_impl.h"
17 #include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
18 #include "content/browser/frame_host/navigator.h"
19 #include "content/browser/site_instance_impl.h"
20 #include "content/browser/web_contents/web_contents_impl.h"
21 #include "content/common/frame_messages.h"
22 #include "content/common/view_messages.h"
23 #include "content/public/browser/navigation_details.h"
24 #include "content/public/browser/notification_registrar.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/render_view_host.h"
27 #include "content/public/browser/web_contents_delegate.h"
28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/common/page_state.h"
30 #include "content/public/common/url_constants.h"
31 #include "content/public/test/mock_render_process_host.h"
32 #include "content/public/test/test_notification_tracker.h"
33 #include "content/public/test/test_utils.h"
34 #include "content/test/test_render_view_host.h"
35 #include "content/test/test_web_contents.h"
36 #include "net/base/net_util.h"
37 #include "skia/ext/platform_canvas.h"
38 #include "testing/gtest/include/gtest/gtest.h"
40 using base::Time;
42 namespace {
44 // Creates an image with a 1x1 SkBitmap of the specified |color|.
45 gfx::Image CreateImage(SkColor color) {
46 SkBitmap bitmap;
47 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
48 bitmap.allocPixels();
49 bitmap.eraseColor(color);
50 return gfx::Image::CreateFrom1xBitmap(bitmap);
53 // Returns true if images |a| and |b| have the same pixel data.
54 bool DoImagesMatch(const gfx::Image& a, const gfx::Image& b) {
55 // Assume that if the 1x bitmaps match, the images match.
56 SkBitmap a_bitmap = a.AsBitmap();
57 SkBitmap b_bitmap = b.AsBitmap();
59 if (a_bitmap.width() != b_bitmap.width() ||
60 a_bitmap.height() != b_bitmap.height()) {
61 return false;
63 SkAutoLockPixels a_bitmap_lock(a_bitmap);
64 SkAutoLockPixels b_bitmap_lock(b_bitmap);
65 return memcmp(a_bitmap.getPixels(),
66 b_bitmap.getPixels(),
67 a_bitmap.getSize()) == 0;
70 class MockScreenshotManager : public content::NavigationEntryScreenshotManager {
71 public:
72 explicit MockScreenshotManager(content::NavigationControllerImpl* owner)
73 : content::NavigationEntryScreenshotManager(owner),
74 encoding_screenshot_in_progress_(false) {
77 virtual ~MockScreenshotManager() {
80 void TakeScreenshotFor(content::NavigationEntryImpl* entry) {
81 SkBitmap bitmap;
82 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
83 bitmap.allocPixels();
84 bitmap.eraseARGB(0, 0, 0, 0);
85 encoding_screenshot_in_progress_ = true;
86 OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
87 WaitUntilScreenshotIsReady();
90 int GetScreenshotCount() {
91 return content::NavigationEntryScreenshotManager::GetScreenshotCount();
94 void WaitUntilScreenshotIsReady() {
95 if (!encoding_screenshot_in_progress_)
96 return;
97 message_loop_runner_ = new content::MessageLoopRunner;
98 message_loop_runner_->Run();
101 private:
102 // Overridden from content::NavigationEntryScreenshotManager:
103 virtual void TakeScreenshotImpl(
104 content::RenderViewHost* host,
105 content::NavigationEntryImpl* entry) OVERRIDE {
108 virtual void OnScreenshotSet(content::NavigationEntryImpl* entry) OVERRIDE {
109 encoding_screenshot_in_progress_ = false;
110 NavigationEntryScreenshotManager::OnScreenshotSet(entry);
111 if (message_loop_runner_.get())
112 message_loop_runner_->Quit();
115 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
116 bool encoding_screenshot_in_progress_;
118 DISALLOW_COPY_AND_ASSIGN(MockScreenshotManager);
121 } // namespace
123 namespace content {
125 // TimeSmoother tests ----------------------------------------------------------
127 // With no duplicates, GetSmoothedTime should be the identity
128 // function.
129 TEST(TimeSmoother, Basic) {
130 NavigationControllerImpl::TimeSmoother smoother;
131 for (int64 i = 1; i < 1000; ++i) {
132 base::Time t = base::Time::FromInternalValue(i);
133 EXPECT_EQ(t, smoother.GetSmoothedTime(t));
137 // With a single duplicate and timestamps thereafter increasing by one
138 // microsecond, the smoothed time should always be one behind.
139 TEST(TimeSmoother, SingleDuplicate) {
140 NavigationControllerImpl::TimeSmoother smoother;
141 base::Time t = base::Time::FromInternalValue(1);
142 EXPECT_EQ(t, smoother.GetSmoothedTime(t));
143 for (int64 i = 1; i < 1000; ++i) {
144 base::Time expected_t = base::Time::FromInternalValue(i + 1);
145 t = base::Time::FromInternalValue(i);
146 EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
150 // With k duplicates and timestamps thereafter increasing by one
151 // microsecond, the smoothed time should always be k behind.
152 TEST(TimeSmoother, ManyDuplicates) {
153 const int64 kNumDuplicates = 100;
154 NavigationControllerImpl::TimeSmoother smoother;
155 base::Time t = base::Time::FromInternalValue(1);
156 for (int64 i = 0; i < kNumDuplicates; ++i) {
157 base::Time expected_t = base::Time::FromInternalValue(i + 1);
158 EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
160 for (int64 i = 1; i < 1000; ++i) {
161 base::Time expected_t =
162 base::Time::FromInternalValue(i + kNumDuplicates);
163 t = base::Time::FromInternalValue(i);
164 EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
168 // If the clock jumps far back enough after a run of duplicates, it
169 // should immediately jump to that value.
170 TEST(TimeSmoother, ClockBackwardsJump) {
171 const int64 kNumDuplicates = 100;
172 NavigationControllerImpl::TimeSmoother smoother;
173 base::Time t = base::Time::FromInternalValue(1000);
174 for (int64 i = 0; i < kNumDuplicates; ++i) {
175 base::Time expected_t = base::Time::FromInternalValue(i + 1000);
176 EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
178 t = base::Time::FromInternalValue(500);
179 EXPECT_EQ(t, smoother.GetSmoothedTime(t));
182 // NavigationControllerTest ----------------------------------------------------
184 class NavigationControllerTest
185 : public RenderViewHostImplTestHarness,
186 public WebContentsObserver {
187 public:
188 NavigationControllerTest() : navigation_entry_committed_counter_(0) {
191 virtual void SetUp() OVERRIDE {
192 RenderViewHostImplTestHarness::SetUp();
193 WebContents* web_contents = RenderViewHostImplTestHarness::web_contents();
194 ASSERT_TRUE(web_contents); // The WebContents should be created by now.
195 WebContentsObserver::Observe(web_contents);
198 // WebContentsObserver:
199 virtual void DidStartNavigationToPendingEntry(
200 const GURL& url,
201 NavigationController::ReloadType reload_type) OVERRIDE {
202 navigated_url_ = url;
205 virtual void NavigationEntryCommitted(
206 const LoadCommittedDetails& load_details) OVERRIDE {
207 navigation_entry_committed_counter_++;
210 const GURL& navigated_url() const {
211 return navigated_url_;
214 NavigationControllerImpl& controller_impl() {
215 return static_cast<NavigationControllerImpl&>(controller());
218 protected:
219 GURL navigated_url_;
220 size_t navigation_entry_committed_counter_;
223 void RegisterForAllNavNotifications(TestNotificationTracker* tracker,
224 NavigationController* controller) {
225 tracker->ListenFor(NOTIFICATION_NAV_LIST_PRUNED,
226 Source<NavigationController>(controller));
227 tracker->ListenFor(NOTIFICATION_NAV_ENTRY_CHANGED,
228 Source<NavigationController>(controller));
231 SiteInstance* GetSiteInstanceFromEntry(NavigationEntry* entry) {
232 return NavigationEntryImpl::FromNavigationEntry(entry)->site_instance();
235 class TestWebContentsDelegate : public WebContentsDelegate {
236 public:
237 explicit TestWebContentsDelegate() :
238 navigation_state_change_count_(0) {}
240 int navigation_state_change_count() {
241 return navigation_state_change_count_;
244 // Keep track of whether the tab has notified us of a navigation state change.
245 virtual void NavigationStateChanged(const WebContents* source,
246 unsigned changed_flags) OVERRIDE {
247 navigation_state_change_count_++;
250 private:
251 // The number of times NavigationStateChanged has been called.
252 int navigation_state_change_count_;
255 // -----------------------------------------------------------------------------
257 TEST_F(NavigationControllerTest, Defaults) {
258 NavigationControllerImpl& controller = controller_impl();
260 EXPECT_FALSE(controller.GetPendingEntry());
261 EXPECT_FALSE(controller.GetVisibleEntry());
262 EXPECT_FALSE(controller.GetLastCommittedEntry());
263 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
264 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
265 EXPECT_EQ(controller.GetEntryCount(), 0);
266 EXPECT_FALSE(controller.CanGoBack());
267 EXPECT_FALSE(controller.CanGoForward());
270 TEST_F(NavigationControllerTest, GoToOffset) {
271 NavigationControllerImpl& controller = controller_impl();
272 TestNotificationTracker notifications;
273 RegisterForAllNavNotifications(&notifications, &controller);
275 const int kNumUrls = 5;
276 std::vector<GURL> urls(kNumUrls);
277 for (int i = 0; i < kNumUrls; ++i) {
278 urls[i] = GURL(base::StringPrintf("http://www.a.com/%d", i));
281 main_test_rfh()->SendNavigate(0, urls[0]);
282 EXPECT_EQ(1U, navigation_entry_committed_counter_);
283 navigation_entry_committed_counter_ = 0;
284 EXPECT_EQ(urls[0], controller.GetVisibleEntry()->GetVirtualURL());
285 EXPECT_FALSE(controller.CanGoBack());
286 EXPECT_FALSE(controller.CanGoForward());
287 EXPECT_FALSE(controller.CanGoToOffset(1));
289 for (int i = 1; i <= 4; ++i) {
290 main_test_rfh()->SendNavigate(i, urls[i]);
291 EXPECT_EQ(1U, navigation_entry_committed_counter_);
292 navigation_entry_committed_counter_ = 0;
293 EXPECT_EQ(urls[i], controller.GetVisibleEntry()->GetVirtualURL());
294 EXPECT_TRUE(controller.CanGoToOffset(-i));
295 EXPECT_FALSE(controller.CanGoToOffset(-(i + 1)));
296 EXPECT_FALSE(controller.CanGoToOffset(1));
299 // We have loaded 5 pages, and are currently at the last-loaded page.
300 int url_index = 4;
302 enum Tests {
303 GO_TO_MIDDLE_PAGE = -2,
304 GO_FORWARDS = 1,
305 GO_BACKWARDS = -1,
306 GO_TO_BEGINNING = -2,
307 GO_TO_END = 4,
308 NUM_TESTS = 5,
311 const int test_offsets[NUM_TESTS] = {
312 GO_TO_MIDDLE_PAGE,
313 GO_FORWARDS,
314 GO_BACKWARDS,
315 GO_TO_BEGINNING,
316 GO_TO_END
319 for (int test = 0; test < NUM_TESTS; ++test) {
320 int offset = test_offsets[test];
321 controller.GoToOffset(offset);
322 url_index += offset;
323 // Check that the GoToOffset will land on the expected page.
324 EXPECT_EQ(urls[url_index], controller.GetPendingEntry()->GetVirtualURL());
325 main_test_rfh()->SendNavigate(url_index, urls[url_index]);
326 EXPECT_EQ(1U, navigation_entry_committed_counter_);
327 navigation_entry_committed_counter_ = 0;
328 // Check that we can go to any valid offset into the history.
329 for (size_t j = 0; j < urls.size(); ++j)
330 EXPECT_TRUE(controller.CanGoToOffset(j - url_index));
331 // Check that we can't go beyond the beginning or end of the history.
332 EXPECT_FALSE(controller.CanGoToOffset(-(url_index + 1)));
333 EXPECT_FALSE(controller.CanGoToOffset(urls.size() - url_index));
337 TEST_F(NavigationControllerTest, LoadURL) {
338 NavigationControllerImpl& controller = controller_impl();
339 TestNotificationTracker notifications;
340 RegisterForAllNavNotifications(&notifications, &controller);
342 const GURL url1("http://foo1");
343 const GURL url2("http://foo2");
345 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
346 // Creating a pending notification should not have issued any of the
347 // notifications we're listening for.
348 EXPECT_EQ(0U, notifications.size());
350 // The load should now be pending.
351 EXPECT_EQ(controller.GetEntryCount(), 0);
352 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
353 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
354 EXPECT_FALSE(controller.GetLastCommittedEntry());
355 ASSERT_TRUE(controller.GetPendingEntry());
356 EXPECT_EQ(controller.GetPendingEntry(), controller.GetVisibleEntry());
357 EXPECT_FALSE(controller.CanGoBack());
358 EXPECT_FALSE(controller.CanGoForward());
359 EXPECT_EQ(contents()->GetMaxPageID(), -1);
361 // Neither the timestamp nor the status code should have been set yet.
362 EXPECT_TRUE(controller.GetPendingEntry()->GetTimestamp().is_null());
363 EXPECT_EQ(0, controller.GetPendingEntry()->GetHttpStatusCode());
365 // We should have gotten no notifications from the preceeding checks.
366 EXPECT_EQ(0U, notifications.size());
368 main_test_rfh()->SendNavigate(0, url1);
369 EXPECT_EQ(1U, navigation_entry_committed_counter_);
370 navigation_entry_committed_counter_ = 0;
372 // The load should now be committed.
373 EXPECT_EQ(controller.GetEntryCount(), 1);
374 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
375 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
376 EXPECT_TRUE(controller.GetLastCommittedEntry());
377 EXPECT_FALSE(controller.GetPendingEntry());
378 ASSERT_TRUE(controller.GetVisibleEntry());
379 EXPECT_FALSE(controller.CanGoBack());
380 EXPECT_FALSE(controller.CanGoForward());
381 EXPECT_EQ(contents()->GetMaxPageID(), 0);
382 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
383 controller.GetLastCommittedEntry())->bindings());
385 // The timestamp should have been set.
386 EXPECT_FALSE(controller.GetVisibleEntry()->GetTimestamp().is_null());
388 // Load another...
389 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
391 // The load should now be pending.
392 EXPECT_EQ(controller.GetEntryCount(), 1);
393 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
394 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
395 EXPECT_TRUE(controller.GetLastCommittedEntry());
396 ASSERT_TRUE(controller.GetPendingEntry());
397 EXPECT_EQ(controller.GetPendingEntry(), controller.GetVisibleEntry());
398 // TODO(darin): maybe this should really be true?
399 EXPECT_FALSE(controller.CanGoBack());
400 EXPECT_FALSE(controller.CanGoForward());
401 EXPECT_EQ(contents()->GetMaxPageID(), 0);
403 EXPECT_TRUE(controller.GetPendingEntry()->GetTimestamp().is_null());
405 // Simulate the beforeunload ack for the cross-site transition, and then the
406 // commit.
407 test_rvh()->SendBeforeUnloadACK(true);
408 static_cast<TestRenderViewHost*>(
409 contents()->GetPendingRenderViewHost())->SendNavigate(1, url2);
410 EXPECT_EQ(1U, navigation_entry_committed_counter_);
411 navigation_entry_committed_counter_ = 0;
413 // The load should now be committed.
414 EXPECT_EQ(controller.GetEntryCount(), 2);
415 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
416 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
417 EXPECT_TRUE(controller.GetLastCommittedEntry());
418 EXPECT_FALSE(controller.GetPendingEntry());
419 ASSERT_TRUE(controller.GetVisibleEntry());
420 EXPECT_TRUE(controller.CanGoBack());
421 EXPECT_FALSE(controller.CanGoForward());
422 EXPECT_EQ(contents()->GetMaxPageID(), 1);
424 EXPECT_FALSE(controller.GetVisibleEntry()->GetTimestamp().is_null());
427 namespace {
429 base::Time GetFixedTime(base::Time time) {
430 return time;
433 } // namespace
435 TEST_F(NavigationControllerTest, LoadURLSameTime) {
436 NavigationControllerImpl& controller = controller_impl();
437 TestNotificationTracker notifications;
438 RegisterForAllNavNotifications(&notifications, &controller);
440 // Set the clock to always return a timestamp of 1.
441 controller.SetGetTimestampCallbackForTest(
442 base::Bind(&GetFixedTime, base::Time::FromInternalValue(1)));
444 const GURL url1("http://foo1");
445 const GURL url2("http://foo2");
447 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
449 main_test_rfh()->SendNavigate(0, url1);
450 EXPECT_EQ(1U, navigation_entry_committed_counter_);
451 navigation_entry_committed_counter_ = 0;
453 // Load another...
454 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
456 // Simulate the beforeunload ack for the cross-site transition, and then the
457 // commit.
458 test_rvh()->SendBeforeUnloadACK(true);
459 main_test_rfh()->SendNavigate(1, url2);
460 EXPECT_EQ(1U, navigation_entry_committed_counter_);
461 navigation_entry_committed_counter_ = 0;
463 // The two loads should now be committed.
464 ASSERT_EQ(controller.GetEntryCount(), 2);
466 // Timestamps should be distinct despite the clock returning the
467 // same value.
468 EXPECT_EQ(1u,
469 controller.GetEntryAtIndex(0)->GetTimestamp().ToInternalValue());
470 EXPECT_EQ(2u,
471 controller.GetEntryAtIndex(1)->GetTimestamp().ToInternalValue());
474 void CheckNavigationEntryMatchLoadParams(
475 NavigationController::LoadURLParams& load_params,
476 NavigationEntryImpl* entry) {
477 EXPECT_EQ(load_params.url, entry->GetURL());
478 EXPECT_EQ(load_params.referrer.url, entry->GetReferrer().url);
479 EXPECT_EQ(load_params.referrer.policy, entry->GetReferrer().policy);
480 EXPECT_EQ(load_params.transition_type, entry->GetTransitionType());
481 EXPECT_EQ(load_params.extra_headers, entry->extra_headers());
483 EXPECT_EQ(load_params.is_renderer_initiated, entry->is_renderer_initiated());
484 EXPECT_EQ(load_params.base_url_for_data_url, entry->GetBaseURLForDataURL());
485 if (!load_params.virtual_url_for_data_url.is_empty()) {
486 EXPECT_EQ(load_params.virtual_url_for_data_url, entry->GetVirtualURL());
488 if (NavigationController::UA_OVERRIDE_INHERIT !=
489 load_params.override_user_agent) {
490 bool should_override = (NavigationController::UA_OVERRIDE_TRUE ==
491 load_params.override_user_agent);
492 EXPECT_EQ(should_override, entry->GetIsOverridingUserAgent());
494 EXPECT_EQ(load_params.browser_initiated_post_data,
495 entry->GetBrowserInitiatedPostData());
496 EXPECT_EQ(load_params.transferred_global_request_id,
497 entry->transferred_global_request_id());
500 TEST_F(NavigationControllerTest, LoadURLWithParams) {
501 NavigationControllerImpl& controller = controller_impl();
503 NavigationController::LoadURLParams load_params(GURL("http://foo"));
504 load_params.referrer =
505 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault);
506 load_params.transition_type = PAGE_TRANSITION_GENERATED;
507 load_params.extra_headers = "content-type: text/plain";
508 load_params.load_type = NavigationController::LOAD_TYPE_DEFAULT;
509 load_params.is_renderer_initiated = true;
510 load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
511 load_params.transferred_global_request_id = GlobalRequestID(2, 3);
513 controller.LoadURLWithParams(load_params);
514 NavigationEntryImpl* entry =
515 NavigationEntryImpl::FromNavigationEntry(
516 controller.GetPendingEntry());
518 // The timestamp should not have been set yet.
519 ASSERT_TRUE(entry);
520 EXPECT_TRUE(entry->GetTimestamp().is_null());
522 CheckNavigationEntryMatchLoadParams(load_params, entry);
525 TEST_F(NavigationControllerTest, LoadURLWithExtraParams_Data) {
526 NavigationControllerImpl& controller = controller_impl();
528 NavigationController::LoadURLParams load_params(
529 GURL("data:text/html,dataurl"));
530 load_params.load_type = NavigationController::LOAD_TYPE_DATA;
531 load_params.base_url_for_data_url = GURL("http://foo");
532 load_params.virtual_url_for_data_url = GURL(kAboutBlankURL);
533 load_params.override_user_agent = NavigationController::UA_OVERRIDE_FALSE;
535 controller.LoadURLWithParams(load_params);
536 NavigationEntryImpl* entry =
537 NavigationEntryImpl::FromNavigationEntry(
538 controller.GetPendingEntry());
540 CheckNavigationEntryMatchLoadParams(load_params, entry);
543 TEST_F(NavigationControllerTest, LoadURLWithExtraParams_HttpPost) {
544 NavigationControllerImpl& controller = controller_impl();
546 NavigationController::LoadURLParams load_params(GURL("https://posturl"));
547 load_params.transition_type = PAGE_TRANSITION_TYPED;
548 load_params.load_type =
549 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
550 load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
553 const unsigned char* raw_data =
554 reinterpret_cast<const unsigned char*>("d\n\0a2");
555 const int length = 5;
556 std::vector<unsigned char> post_data_vector(raw_data, raw_data+length);
557 scoped_refptr<base::RefCountedBytes> data =
558 base::RefCountedBytes::TakeVector(&post_data_vector);
559 load_params.browser_initiated_post_data = data.get();
561 controller.LoadURLWithParams(load_params);
562 NavigationEntryImpl* entry =
563 NavigationEntryImpl::FromNavigationEntry(
564 controller.GetPendingEntry());
566 CheckNavigationEntryMatchLoadParams(load_params, entry);
569 // Tests what happens when the same page is loaded again. Should not create a
570 // new session history entry. This is what happens when you press enter in the
571 // URL bar to reload: a pending entry is created and then it is discarded when
572 // the load commits (because WebCore didn't actually make a new entry).
573 TEST_F(NavigationControllerTest, LoadURL_SamePage) {
574 NavigationControllerImpl& controller = controller_impl();
575 TestNotificationTracker notifications;
576 RegisterForAllNavNotifications(&notifications, &controller);
578 const GURL url1("http://foo1");
580 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
581 EXPECT_EQ(0U, notifications.size());
582 main_test_rfh()->SendNavigate(0, url1);
583 EXPECT_EQ(1U, navigation_entry_committed_counter_);
584 navigation_entry_committed_counter_ = 0;
586 ASSERT_TRUE(controller.GetVisibleEntry());
587 const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
588 EXPECT_FALSE(timestamp.is_null());
590 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
591 EXPECT_EQ(0U, notifications.size());
592 main_test_rfh()->SendNavigate(0, url1);
593 EXPECT_EQ(1U, navigation_entry_committed_counter_);
594 navigation_entry_committed_counter_ = 0;
596 // We should not have produced a new session history entry.
597 EXPECT_EQ(controller.GetEntryCount(), 1);
598 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
599 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
600 EXPECT_TRUE(controller.GetLastCommittedEntry());
601 EXPECT_FALSE(controller.GetPendingEntry());
602 ASSERT_TRUE(controller.GetVisibleEntry());
603 EXPECT_FALSE(controller.CanGoBack());
604 EXPECT_FALSE(controller.CanGoForward());
606 // The timestamp should have been updated.
608 // TODO(akalin): Change this EXPECT_GE (and other similar ones) to
609 // EXPECT_GT once we guarantee that timestamps are unique.
610 EXPECT_GE(controller.GetVisibleEntry()->GetTimestamp(), timestamp);
613 // Load the same page twice, once as a GET and once as a POST.
614 // We should update the post state on the NavigationEntry.
615 TEST_F(NavigationControllerTest, LoadURL_SamePage_DifferentMethod) {
616 NavigationControllerImpl& controller = controller_impl();
617 TestNotificationTracker notifications;
618 RegisterForAllNavNotifications(&notifications, &controller);
620 const GURL url1("http://foo1");
622 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
623 FrameHostMsg_DidCommitProvisionalLoad_Params params;
624 params.page_id = 0;
625 params.url = url1;
626 params.transition = PAGE_TRANSITION_TYPED;
627 params.is_post = true;
628 params.post_id = 123;
629 params.page_state = PageState::CreateForTesting(url1, false, 0, 0);
630 main_test_rfh()->SendNavigateWithParams(&params);
632 // The post data should be visible.
633 NavigationEntry* entry = controller.GetVisibleEntry();
634 ASSERT_TRUE(entry);
635 EXPECT_TRUE(entry->GetHasPostData());
636 EXPECT_EQ(entry->GetPostID(), 123);
638 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
639 main_test_rfh()->SendNavigate(0, url1);
641 // We should not have produced a new session history entry.
642 ASSERT_EQ(controller.GetVisibleEntry(), entry);
644 // The post data should have been cleared due to the GET.
645 EXPECT_FALSE(entry->GetHasPostData());
646 EXPECT_EQ(entry->GetPostID(), 0);
649 // Tests loading a URL but discarding it before the load commits.
650 TEST_F(NavigationControllerTest, LoadURL_Discarded) {
651 NavigationControllerImpl& controller = controller_impl();
652 TestNotificationTracker notifications;
653 RegisterForAllNavNotifications(&notifications, &controller);
655 const GURL url1("http://foo1");
656 const GURL url2("http://foo2");
658 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
659 EXPECT_EQ(0U, notifications.size());
660 main_test_rfh()->SendNavigate(0, url1);
661 EXPECT_EQ(1U, navigation_entry_committed_counter_);
662 navigation_entry_committed_counter_ = 0;
664 ASSERT_TRUE(controller.GetVisibleEntry());
665 const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
666 EXPECT_FALSE(timestamp.is_null());
668 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
669 controller.DiscardNonCommittedEntries();
670 EXPECT_EQ(0U, notifications.size());
672 // Should not have produced a new session history entry.
673 EXPECT_EQ(controller.GetEntryCount(), 1);
674 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
675 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
676 EXPECT_TRUE(controller.GetLastCommittedEntry());
677 EXPECT_FALSE(controller.GetPendingEntry());
678 ASSERT_TRUE(controller.GetVisibleEntry());
679 EXPECT_FALSE(controller.CanGoBack());
680 EXPECT_FALSE(controller.CanGoForward());
682 // Timestamp should not have changed.
683 EXPECT_EQ(timestamp, controller.GetVisibleEntry()->GetTimestamp());
686 // Tests navigations that come in unrequested. This happens when the user
687 // navigates from the web page, and here we test that there is no pending entry.
688 TEST_F(NavigationControllerTest, LoadURL_NoPending) {
689 NavigationControllerImpl& controller = controller_impl();
690 TestNotificationTracker notifications;
691 RegisterForAllNavNotifications(&notifications, &controller);
693 // First make an existing committed entry.
694 const GURL kExistingURL1("http://eh");
695 controller.LoadURL(
696 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
697 main_test_rfh()->SendNavigate(0, kExistingURL1);
698 EXPECT_EQ(1U, navigation_entry_committed_counter_);
699 navigation_entry_committed_counter_ = 0;
701 // Do a new navigation without making a pending one.
702 const GURL kNewURL("http://see");
703 main_test_rfh()->SendNavigate(99, kNewURL);
705 // There should no longer be any pending entry, and the third navigation we
706 // just made should be committed.
707 EXPECT_EQ(1U, navigation_entry_committed_counter_);
708 navigation_entry_committed_counter_ = 0;
709 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
710 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
711 EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
714 // Tests navigating to a new URL when there is a new pending navigation that is
715 // not the one that just loaded. This will happen if the user types in a URL to
716 // somewhere slow, and then navigates the current page before the typed URL
717 // commits.
718 TEST_F(NavigationControllerTest, LoadURL_NewPending) {
719 NavigationControllerImpl& controller = controller_impl();
720 TestNotificationTracker notifications;
721 RegisterForAllNavNotifications(&notifications, &controller);
723 // First make an existing committed entry.
724 const GURL kExistingURL1("http://eh");
725 controller.LoadURL(
726 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
727 main_test_rfh()->SendNavigate(0, kExistingURL1);
728 EXPECT_EQ(1U, navigation_entry_committed_counter_);
729 navigation_entry_committed_counter_ = 0;
731 // Make a pending entry to somewhere new.
732 const GURL kExistingURL2("http://bee");
733 controller.LoadURL(
734 kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
735 EXPECT_EQ(0U, notifications.size());
737 // After the beforeunload but before it commits, do a new navigation.
738 test_rvh()->SendBeforeUnloadACK(true);
739 const GURL kNewURL("http://see");
740 static_cast<TestRenderViewHost*>(
741 contents()->GetPendingRenderViewHost())->SendNavigate(3, kNewURL);
743 // There should no longer be any pending entry, and the third navigation we
744 // just made should be committed.
745 EXPECT_EQ(1U, navigation_entry_committed_counter_);
746 navigation_entry_committed_counter_ = 0;
747 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
748 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
749 EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
752 // Tests navigating to a new URL when there is a pending back/forward
753 // navigation. This will happen if the user hits back, but before that commits,
754 // they navigate somewhere new.
755 TEST_F(NavigationControllerTest, LoadURL_ExistingPending) {
756 NavigationControllerImpl& controller = controller_impl();
757 TestNotificationTracker notifications;
758 RegisterForAllNavNotifications(&notifications, &controller);
760 // First make some history.
761 const GURL kExistingURL1("http://foo/eh");
762 controller.LoadURL(
763 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
764 main_test_rfh()->SendNavigate(0, kExistingURL1);
765 EXPECT_EQ(1U, navigation_entry_committed_counter_);
766 navigation_entry_committed_counter_ = 0;
768 const GURL kExistingURL2("http://foo/bee");
769 controller.LoadURL(
770 kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
771 main_test_rfh()->SendNavigate(1, kExistingURL2);
772 EXPECT_EQ(1U, navigation_entry_committed_counter_);
773 navigation_entry_committed_counter_ = 0;
775 // Now make a pending back/forward navigation. The zeroth entry should be
776 // pending.
777 controller.GoBack();
778 EXPECT_EQ(0U, notifications.size());
779 EXPECT_EQ(0, controller.GetPendingEntryIndex());
780 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
782 // Before that commits, do a new navigation.
783 const GURL kNewURL("http://foo/see");
784 LoadCommittedDetails details;
785 main_test_rfh()->SendNavigate(3, kNewURL);
787 // There should no longer be any pending entry, and the third navigation we
788 // just made should be committed.
789 EXPECT_EQ(1U, navigation_entry_committed_counter_);
790 navigation_entry_committed_counter_ = 0;
791 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
792 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
793 EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
796 // Tests navigating to a new URL when there is a pending back/forward
797 // navigation to a cross-process, privileged URL. This will happen if the user
798 // hits back, but before that commits, they navigate somewhere new.
799 TEST_F(NavigationControllerTest, LoadURL_PrivilegedPending) {
800 NavigationControllerImpl& controller = controller_impl();
801 TestNotificationTracker notifications;
802 RegisterForAllNavNotifications(&notifications, &controller);
804 // First make some history, starting with a privileged URL.
805 const GURL kExistingURL1("http://privileged");
806 controller.LoadURL(
807 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
808 // Pretend it has bindings so we can tell if we incorrectly copy it.
809 test_rvh()->AllowBindings(2);
810 main_test_rfh()->SendNavigate(0, kExistingURL1);
811 EXPECT_EQ(1U, navigation_entry_committed_counter_);
812 navigation_entry_committed_counter_ = 0;
814 // Navigate cross-process to a second URL.
815 const GURL kExistingURL2("http://foo/eh");
816 controller.LoadURL(
817 kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
818 test_rvh()->SendBeforeUnloadACK(true);
819 TestRenderViewHost* foo_rvh = static_cast<TestRenderViewHost*>(
820 contents()->GetPendingRenderViewHost());
821 foo_rvh->SendNavigate(1, kExistingURL2);
822 EXPECT_EQ(1U, navigation_entry_committed_counter_);
823 navigation_entry_committed_counter_ = 0;
825 // Now make a pending back/forward navigation to a privileged entry.
826 // The zeroth entry should be pending.
827 controller.GoBack();
828 foo_rvh->SendBeforeUnloadACK(true);
829 EXPECT_EQ(0U, notifications.size());
830 EXPECT_EQ(0, controller.GetPendingEntryIndex());
831 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
832 EXPECT_EQ(2, NavigationEntryImpl::FromNavigationEntry(
833 controller.GetPendingEntry())->bindings());
835 // Before that commits, do a new navigation.
836 const GURL kNewURL("http://foo/bee");
837 LoadCommittedDetails details;
838 foo_rvh->SendNavigate(3, kNewURL);
840 // There should no longer be any pending entry, and the third navigation we
841 // just made should be committed.
842 EXPECT_EQ(1U, navigation_entry_committed_counter_);
843 navigation_entry_committed_counter_ = 0;
844 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
845 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
846 EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL());
847 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
848 controller.GetLastCommittedEntry())->bindings());
851 // Tests navigating to an existing URL when there is a pending new navigation.
852 // This will happen if the user enters a URL, but before that commits, the
853 // current page fires history.back().
854 TEST_F(NavigationControllerTest, LoadURL_BackPreemptsPending) {
855 NavigationControllerImpl& controller = controller_impl();
856 TestNotificationTracker notifications;
857 RegisterForAllNavNotifications(&notifications, &controller);
859 // First make some history.
860 const GURL kExistingURL1("http://foo/eh");
861 controller.LoadURL(
862 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
863 main_test_rfh()->SendNavigate(0, kExistingURL1);
864 EXPECT_EQ(1U, navigation_entry_committed_counter_);
865 navigation_entry_committed_counter_ = 0;
867 const GURL kExistingURL2("http://foo/bee");
868 controller.LoadURL(
869 kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
870 main_test_rfh()->SendNavigate(1, kExistingURL2);
871 EXPECT_EQ(1U, navigation_entry_committed_counter_);
872 navigation_entry_committed_counter_ = 0;
874 // Now make a pending new navigation.
875 const GURL kNewURL("http://foo/see");
876 controller.LoadURL(
877 kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
878 EXPECT_EQ(0U, notifications.size());
879 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
880 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
882 // Before that commits, a back navigation from the renderer commits.
883 main_test_rfh()->SendNavigate(0, kExistingURL1);
885 // There should no longer be any pending entry, and the back navigation we
886 // just made should be committed.
887 EXPECT_EQ(1U, navigation_entry_committed_counter_);
888 navigation_entry_committed_counter_ = 0;
889 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
890 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
891 EXPECT_EQ(kExistingURL1, controller.GetVisibleEntry()->GetURL());
894 // Tests an ignored navigation when there is a pending new navigation.
895 // This will happen if the user enters a URL, but before that commits, the
896 // current blank page reloads. See http://crbug.com/77507.
897 TEST_F(NavigationControllerTest, LoadURL_IgnorePreemptsPending) {
898 NavigationControllerImpl& controller = controller_impl();
899 TestNotificationTracker notifications;
900 RegisterForAllNavNotifications(&notifications, &controller);
902 // Set a WebContentsDelegate to listen for state changes.
903 scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
904 EXPECT_FALSE(contents()->GetDelegate());
905 contents()->SetDelegate(delegate.get());
907 // Without any navigations, the renderer starts at about:blank.
908 const GURL kExistingURL(kAboutBlankURL);
910 // Now make a pending new navigation.
911 const GURL kNewURL("http://eh");
912 controller.LoadURL(
913 kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
914 EXPECT_EQ(0U, notifications.size());
915 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
916 EXPECT_TRUE(controller.GetPendingEntry());
917 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
918 EXPECT_EQ(1, delegate->navigation_state_change_count());
920 // Before that commits, a document.write and location.reload can cause the
921 // renderer to send a FrameNavigate with page_id -1.
922 main_test_rfh()->SendNavigate(-1, kExistingURL);
924 // This should clear the pending entry and notify of a navigation state
925 // change, so that we do not keep displaying kNewURL.
926 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
927 EXPECT_FALSE(controller.GetPendingEntry());
928 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
929 EXPECT_EQ(2, delegate->navigation_state_change_count());
931 contents()->SetDelegate(NULL);
934 // Tests that the pending entry state is correct after an abort.
935 // We do not want to clear the pending entry, so that the user doesn't
936 // lose a typed URL. (See http://crbug.com/9682.)
937 TEST_F(NavigationControllerTest, LoadURL_AbortDoesntCancelPending) {
938 NavigationControllerImpl& controller = controller_impl();
939 TestNotificationTracker notifications;
940 RegisterForAllNavNotifications(&notifications, &controller);
942 // Set a WebContentsDelegate to listen for state changes.
943 scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
944 EXPECT_FALSE(contents()->GetDelegate());
945 contents()->SetDelegate(delegate.get());
947 // Start with a pending new navigation.
948 const GURL kNewURL("http://eh");
949 controller.LoadURL(
950 kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
951 EXPECT_EQ(0U, notifications.size());
952 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
953 EXPECT_TRUE(controller.GetPendingEntry());
954 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
955 EXPECT_EQ(1, delegate->navigation_state_change_count());
957 // It may abort before committing, if it's a download or due to a stop or
958 // a new navigation from the user.
959 FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
960 params.error_code = net::ERR_ABORTED;
961 params.error_description = base::string16();
962 params.url = kNewURL;
963 params.showing_repost_interstitial = false;
964 main_test_rfh()->OnMessageReceived(
965 FrameHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
966 params));
968 // This should not clear the pending entry or notify of a navigation state
969 // change, so that we keep displaying kNewURL (until the user clears it).
970 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
971 EXPECT_TRUE(controller.GetPendingEntry());
972 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
973 EXPECT_EQ(1, delegate->navigation_state_change_count());
974 NavigationEntry* pending_entry = controller.GetPendingEntry();
976 // Ensure that a reload keeps the same pending entry.
977 controller.Reload(true);
978 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
979 EXPECT_TRUE(controller.GetPendingEntry());
980 EXPECT_EQ(pending_entry, controller.GetPendingEntry());
981 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
983 contents()->SetDelegate(NULL);
986 // Tests that the pending URL is not visible during a renderer-initiated
987 // redirect and abort. See http://crbug.com/83031.
988 TEST_F(NavigationControllerTest, LoadURL_RedirectAbortDoesntShowPendingURL) {
989 NavigationControllerImpl& controller = controller_impl();
990 TestNotificationTracker notifications;
991 RegisterForAllNavNotifications(&notifications, &controller);
993 // First make an existing committed entry.
994 const GURL kExistingURL("http://foo/eh");
995 controller.LoadURL(kExistingURL, content::Referrer(),
996 content::PAGE_TRANSITION_TYPED, std::string());
997 main_test_rfh()->SendNavigate(0, kExistingURL);
998 EXPECT_EQ(1U, navigation_entry_committed_counter_);
999 navigation_entry_committed_counter_ = 0;
1001 // Set a WebContentsDelegate to listen for state changes.
1002 scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
1003 EXPECT_FALSE(contents()->GetDelegate());
1004 contents()->SetDelegate(delegate.get());
1006 // Now make a pending new navigation, initiated by the renderer.
1007 const GURL kNewURL("http://foo/bee");
1008 NavigationController::LoadURLParams load_url_params(kNewURL);
1009 load_url_params.transition_type = PAGE_TRANSITION_TYPED;
1010 load_url_params.is_renderer_initiated = true;
1011 controller.LoadURLWithParams(load_url_params);
1012 EXPECT_EQ(0U, notifications.size());
1013 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1014 EXPECT_TRUE(controller.GetPendingEntry());
1015 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
1016 EXPECT_EQ(0, delegate->navigation_state_change_count());
1018 // The visible entry should be the last committed URL, not the pending one.
1019 EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL());
1021 // Now the navigation redirects.
1022 const GURL kRedirectURL("http://foo/see");
1023 main_test_rfh()->OnMessageReceived(
1024 FrameHostMsg_DidRedirectProvisionalLoad(0, // routing_id
1025 -1, // pending page_id
1026 kNewURL, // old url
1027 kRedirectURL)); // new url
1029 // We don't want to change the NavigationEntry's url, in case it cancels.
1030 // Prevents regression of http://crbug.com/77786.
1031 EXPECT_EQ(kNewURL, controller.GetPendingEntry()->GetURL());
1033 // It may abort before committing, if it's a download or due to a stop or
1034 // a new navigation from the user.
1035 FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
1036 params.error_code = net::ERR_ABORTED;
1037 params.error_description = base::string16();
1038 params.url = kRedirectURL;
1039 params.showing_repost_interstitial = false;
1040 main_test_rfh()->OnMessageReceived(
1041 FrameHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
1042 params));
1044 // Because the pending entry is renderer initiated and not visible, we
1045 // clear it when it fails.
1046 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1047 EXPECT_FALSE(controller.GetPendingEntry());
1048 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
1049 EXPECT_EQ(1, delegate->navigation_state_change_count());
1051 // The visible entry should be the last committed URL, not the pending one,
1052 // so that no spoof is possible.
1053 EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL());
1055 contents()->SetDelegate(NULL);
1058 // Ensure that NavigationEntries track which bindings their RenderViewHost had
1059 // at the time they committed. http://crbug.com/173672.
1060 TEST_F(NavigationControllerTest, LoadURL_WithBindings) {
1061 NavigationControllerImpl& controller = controller_impl();
1062 TestNotificationTracker notifications;
1063 RegisterForAllNavNotifications(&notifications, &controller);
1064 std::vector<GURL> url_chain;
1066 const GURL url1("http://foo1");
1067 const GURL url2("http://foo2");
1069 // Navigate to a first, unprivileged URL.
1070 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1071 EXPECT_EQ(NavigationEntryImpl::kInvalidBindings,
1072 NavigationEntryImpl::FromNavigationEntry(
1073 controller.GetPendingEntry())->bindings());
1075 // Commit.
1076 TestRenderViewHost* orig_rvh = static_cast<TestRenderViewHost*>(test_rvh());
1077 orig_rvh->SendNavigate(0, url1);
1078 EXPECT_EQ(controller.GetEntryCount(), 1);
1079 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
1080 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
1081 controller.GetLastCommittedEntry())->bindings());
1083 // Manually increase the number of active views in the SiteInstance
1084 // that orig_rvh belongs to, to prevent it from being destroyed when
1085 // it gets swapped out, so that we can reuse orig_rvh when the
1086 // controller goes back.
1087 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
1088 increment_active_view_count();
1090 // Navigate to a second URL, simulate the beforeunload ack for the cross-site
1091 // transition, run the unload handler, and set bindings on the pending
1092 // RenderViewHost to simulate a privileged url.
1093 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1094 orig_rvh->SendBeforeUnloadACK(true);
1095 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1096 contents()->GetRenderManagerForTesting()->pending_frame_host(),
1097 GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
1098 url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
1099 TestRenderViewHost* new_rvh =
1100 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
1101 new_rvh->AllowBindings(1);
1102 new_rvh->SendNavigate(1, url2);
1104 // The second load should be committed, and bindings should be remembered.
1105 EXPECT_EQ(controller.GetEntryCount(), 2);
1106 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
1107 EXPECT_TRUE(controller.CanGoBack());
1108 EXPECT_EQ(1, NavigationEntryImpl::FromNavigationEntry(
1109 controller.GetLastCommittedEntry())->bindings());
1111 // Going back, the first entry should still appear unprivileged.
1112 controller.GoBack();
1113 new_rvh->SendBeforeUnloadACK(true);
1114 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1115 contents()->GetRenderManagerForTesting()->pending_frame_host(),
1116 GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
1117 url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
1118 orig_rvh->SendNavigate(0, url1);
1119 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
1120 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
1121 controller.GetLastCommittedEntry())->bindings());
1124 TEST_F(NavigationControllerTest, Reload) {
1125 NavigationControllerImpl& controller = controller_impl();
1126 TestNotificationTracker notifications;
1127 RegisterForAllNavNotifications(&notifications, &controller);
1129 const GURL url1("http://foo1");
1131 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1132 EXPECT_EQ(0U, notifications.size());
1133 main_test_rfh()->SendNavigate(0, url1);
1134 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1135 navigation_entry_committed_counter_ = 0;
1136 ASSERT_TRUE(controller.GetVisibleEntry());
1137 controller.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
1138 controller.Reload(true);
1139 EXPECT_EQ(0U, notifications.size());
1141 const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp();
1142 EXPECT_FALSE(timestamp.is_null());
1144 // The reload is pending.
1145 EXPECT_EQ(controller.GetEntryCount(), 1);
1146 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1147 EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
1148 EXPECT_TRUE(controller.GetLastCommittedEntry());
1149 EXPECT_TRUE(controller.GetPendingEntry());
1150 EXPECT_FALSE(controller.CanGoBack());
1151 EXPECT_FALSE(controller.CanGoForward());
1152 // Make sure the title has been cleared (will be redrawn just after reload).
1153 // Avoids a stale cached title when the new page being reloaded has no title.
1154 // See http://crbug.com/96041.
1155 EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty());
1157 main_test_rfh()->SendNavigate(0, url1);
1158 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1159 navigation_entry_committed_counter_ = 0;
1161 // Now the reload is committed.
1162 EXPECT_EQ(controller.GetEntryCount(), 1);
1163 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1164 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1165 EXPECT_TRUE(controller.GetLastCommittedEntry());
1166 EXPECT_FALSE(controller.GetPendingEntry());
1167 EXPECT_FALSE(controller.CanGoBack());
1168 EXPECT_FALSE(controller.CanGoForward());
1170 // The timestamp should have been updated.
1171 ASSERT_TRUE(controller.GetVisibleEntry());
1172 EXPECT_GE(controller.GetVisibleEntry()->GetTimestamp(), timestamp);
1175 // Tests what happens when a reload navigation produces a new page.
1176 TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) {
1177 NavigationControllerImpl& controller = controller_impl();
1178 TestNotificationTracker notifications;
1179 RegisterForAllNavNotifications(&notifications, &controller);
1181 const GURL url1("http://foo1");
1182 const GURL url2("http://foo2");
1184 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1185 main_test_rfh()->SendNavigate(0, url1);
1186 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1187 navigation_entry_committed_counter_ = 0;
1189 controller.Reload(true);
1190 EXPECT_EQ(0U, notifications.size());
1192 main_test_rfh()->SendNavigate(1, url2);
1193 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1194 navigation_entry_committed_counter_ = 0;
1196 // Now the reload is committed.
1197 EXPECT_EQ(controller.GetEntryCount(), 2);
1198 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1199 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1200 EXPECT_TRUE(controller.GetLastCommittedEntry());
1201 EXPECT_FALSE(controller.GetPendingEntry());
1202 EXPECT_TRUE(controller.CanGoBack());
1203 EXPECT_FALSE(controller.CanGoForward());
1206 // This test ensures that when a guest renderer reloads, the reload goes through
1207 // without ending up in the "we have a wrong process for the URL" branch in
1208 // NavigationControllerImpl::ReloadInternal.
1209 TEST_F(NavigationControllerTest, ReloadWithGuest) {
1210 NavigationControllerImpl& controller = controller_impl();
1212 const GURL url1("http://foo1");
1213 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1214 main_test_rfh()->SendNavigate(0, url1);
1215 ASSERT_TRUE(controller.GetVisibleEntry());
1217 // Make the entry believe its RenderProcessHost is a guest.
1218 NavigationEntryImpl* entry1 =
1219 NavigationEntryImpl::FromNavigationEntry(controller.GetVisibleEntry());
1220 reinterpret_cast<MockRenderProcessHost*>(
1221 entry1->site_instance()->GetProcess())->SetIsGuest(true);
1223 // And reload.
1224 controller.Reload(true);
1226 // The reload is pending. Check that the NavigationEntry didn't get replaced
1227 // because of having the wrong process.
1228 EXPECT_EQ(controller.GetEntryCount(), 1);
1229 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1230 EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
1232 NavigationEntryImpl* entry2 =
1233 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry());
1234 EXPECT_EQ(entry1, entry2);
1237 #if !defined(OS_ANDROID) // http://crbug.com/157428
1238 TEST_F(NavigationControllerTest, ReloadOriginalRequestURL) {
1239 NavigationControllerImpl& controller = controller_impl();
1240 TestNotificationTracker notifications;
1241 RegisterForAllNavNotifications(&notifications, &controller);
1243 const GURL original_url("http://foo1");
1244 const GURL final_url("http://foo2");
1246 // Load up the original URL, but get redirected.
1247 controller.LoadURL(
1248 original_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1249 EXPECT_EQ(0U, notifications.size());
1250 main_test_rfh()->SendNavigateWithOriginalRequestURL(
1251 0, final_url, original_url);
1252 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1253 navigation_entry_committed_counter_ = 0;
1255 // The NavigationEntry should save both the original URL and the final
1256 // redirected URL.
1257 EXPECT_EQ(
1258 original_url, controller.GetVisibleEntry()->GetOriginalRequestURL());
1259 EXPECT_EQ(final_url, controller.GetVisibleEntry()->GetURL());
1261 // Reload using the original URL.
1262 controller.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
1263 controller.ReloadOriginalRequestURL(false);
1264 EXPECT_EQ(0U, notifications.size());
1266 // The reload is pending. The request should point to the original URL.
1267 EXPECT_EQ(original_url, navigated_url());
1268 EXPECT_EQ(controller.GetEntryCount(), 1);
1269 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1270 EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
1271 EXPECT_TRUE(controller.GetLastCommittedEntry());
1272 EXPECT_TRUE(controller.GetPendingEntry());
1273 EXPECT_FALSE(controller.CanGoBack());
1274 EXPECT_FALSE(controller.CanGoForward());
1276 // Make sure the title has been cleared (will be redrawn just after reload).
1277 // Avoids a stale cached title when the new page being reloaded has no title.
1278 // See http://crbug.com/96041.
1279 EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty());
1281 // Send that the navigation has proceeded; say it got redirected again.
1282 main_test_rfh()->SendNavigate(0, final_url);
1283 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1284 navigation_entry_committed_counter_ = 0;
1286 // Now the reload is committed.
1287 EXPECT_EQ(controller.GetEntryCount(), 1);
1288 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1289 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1290 EXPECT_TRUE(controller.GetLastCommittedEntry());
1291 EXPECT_FALSE(controller.GetPendingEntry());
1292 EXPECT_FALSE(controller.CanGoBack());
1293 EXPECT_FALSE(controller.CanGoForward());
1296 #endif // !defined(OS_ANDROID)
1298 // Test that certain non-persisted NavigationEntryImpl values get reset after
1299 // commit.
1300 TEST_F(NavigationControllerTest, ResetEntryValuesAfterCommit) {
1301 NavigationControllerImpl& controller = controller_impl();
1302 const GURL url1("http://foo1");
1303 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1305 // Set up some sample values.
1306 const unsigned char* raw_data =
1307 reinterpret_cast<const unsigned char*>("post\n\n\0data");
1308 const int length = 11;
1309 std::vector<unsigned char> post_data_vector(raw_data, raw_data+length);
1310 scoped_refptr<base::RefCountedBytes> post_data =
1311 base::RefCountedBytes::TakeVector(&post_data_vector);
1312 GlobalRequestID transfer_id(3, 4);
1313 std::vector<GURL> redirects;
1314 redirects.push_back(GURL("http://foo2"));
1316 // Set non-persisted values on the pending entry.
1317 NavigationEntryImpl* pending_entry =
1318 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry());
1319 pending_entry->SetBrowserInitiatedPostData(post_data.get());
1320 pending_entry->set_is_renderer_initiated(true);
1321 pending_entry->set_transferred_global_request_id(transfer_id);
1322 pending_entry->set_should_replace_entry(true);
1323 pending_entry->set_should_clear_history_list(true);
1324 EXPECT_EQ(post_data.get(), pending_entry->GetBrowserInitiatedPostData());
1325 EXPECT_TRUE(pending_entry->is_renderer_initiated());
1326 EXPECT_EQ(transfer_id, pending_entry->transferred_global_request_id());
1327 EXPECT_TRUE(pending_entry->should_replace_entry());
1328 EXPECT_TRUE(pending_entry->should_clear_history_list());
1330 main_test_rfh()->SendNavigate(0, url1);
1332 // Certain values that are only used for pending entries get reset after
1333 // commit.
1334 NavigationEntryImpl* committed_entry =
1335 NavigationEntryImpl::FromNavigationEntry(
1336 controller.GetLastCommittedEntry());
1337 EXPECT_FALSE(committed_entry->GetBrowserInitiatedPostData());
1338 EXPECT_FALSE(committed_entry->is_renderer_initiated());
1339 EXPECT_EQ(GlobalRequestID(-1, -1),
1340 committed_entry->transferred_global_request_id());
1341 EXPECT_FALSE(committed_entry->should_replace_entry());
1342 EXPECT_FALSE(committed_entry->should_clear_history_list());
1345 // Test that Redirects are preserved after a commit.
1346 TEST_F(NavigationControllerTest, RedirectsAreNotResetByCommit) {
1347 NavigationControllerImpl& controller = controller_impl();
1348 const GURL url1("http://foo1");
1349 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1351 // Set up some redirect values.
1352 std::vector<GURL> redirects;
1353 redirects.push_back(GURL("http://foo2"));
1355 // Set redirects on the pending entry.
1356 NavigationEntryImpl* pending_entry =
1357 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry());
1358 pending_entry->SetRedirectChain(redirects);
1359 EXPECT_EQ(1U, pending_entry->GetRedirectChain().size());
1360 EXPECT_EQ(GURL("http://foo2"), pending_entry->GetRedirectChain()[0]);
1362 // Normal navigation will preserve redirects in the committed entry.
1363 main_test_rfh()->SendNavigateWithRedirects(0, url1, redirects);
1364 NavigationEntryImpl* committed_entry =
1365 NavigationEntryImpl::FromNavigationEntry(
1366 controller.GetLastCommittedEntry());
1367 ASSERT_EQ(1U, committed_entry->GetRedirectChain().size());
1368 EXPECT_EQ(GURL("http://foo2"), committed_entry->GetRedirectChain()[0]);
1371 // Tests what happens when we navigate back successfully
1372 TEST_F(NavigationControllerTest, Back) {
1373 NavigationControllerImpl& controller = controller_impl();
1374 TestNotificationTracker notifications;
1375 RegisterForAllNavNotifications(&notifications, &controller);
1377 const GURL url1("http://foo1");
1378 main_test_rfh()->SendNavigate(0, url1);
1379 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1380 navigation_entry_committed_counter_ = 0;
1382 const GURL url2("http://foo2");
1383 main_test_rfh()->SendNavigate(1, url2);
1384 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1385 navigation_entry_committed_counter_ = 0;
1387 controller.GoBack();
1388 EXPECT_EQ(0U, notifications.size());
1390 // We should now have a pending navigation to go back.
1391 EXPECT_EQ(controller.GetEntryCount(), 2);
1392 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1393 EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
1394 EXPECT_TRUE(controller.GetLastCommittedEntry());
1395 EXPECT_TRUE(controller.GetPendingEntry());
1396 EXPECT_FALSE(controller.CanGoBack());
1397 EXPECT_FALSE(controller.CanGoToOffset(-1));
1398 EXPECT_TRUE(controller.CanGoForward());
1399 EXPECT_TRUE(controller.CanGoToOffset(1));
1400 EXPECT_FALSE(controller.CanGoToOffset(2)); // Cannot go foward 2 steps.
1402 // Timestamp for entry 1 should be on or after that of entry 0.
1403 EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null());
1404 EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(),
1405 controller.GetEntryAtIndex(0)->GetTimestamp());
1407 main_test_rfh()->SendNavigate(0, url2);
1408 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1409 navigation_entry_committed_counter_ = 0;
1411 // The back navigation completed successfully.
1412 EXPECT_EQ(controller.GetEntryCount(), 2);
1413 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1414 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1415 EXPECT_TRUE(controller.GetLastCommittedEntry());
1416 EXPECT_FALSE(controller.GetPendingEntry());
1417 EXPECT_FALSE(controller.CanGoBack());
1418 EXPECT_FALSE(controller.CanGoToOffset(-1));
1419 EXPECT_TRUE(controller.CanGoForward());
1420 EXPECT_TRUE(controller.CanGoToOffset(1));
1421 EXPECT_FALSE(controller.CanGoToOffset(2)); // Cannot go foward 2 steps.
1423 // Timestamp for entry 0 should be on or after that of entry 1
1424 // (since we went back to it).
1425 EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(),
1426 controller.GetEntryAtIndex(1)->GetTimestamp());
1429 // Tests what happens when a back navigation produces a new page.
1430 TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
1431 NavigationControllerImpl& controller = controller_impl();
1432 TestNotificationTracker notifications;
1433 RegisterForAllNavNotifications(&notifications, &controller);
1435 const GURL url1("http://foo/1");
1436 const GURL url2("http://foo/2");
1437 const GURL url3("http://foo/3");
1439 controller.LoadURL(
1440 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1441 main_test_rfh()->SendNavigate(0, url1);
1442 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1443 navigation_entry_committed_counter_ = 0;
1445 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1446 main_test_rfh()->SendNavigate(1, url2);
1447 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1448 navigation_entry_committed_counter_ = 0;
1450 controller.GoBack();
1451 EXPECT_EQ(0U, notifications.size());
1453 // We should now have a pending navigation to go back.
1454 EXPECT_EQ(controller.GetEntryCount(), 2);
1455 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1456 EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
1457 EXPECT_TRUE(controller.GetLastCommittedEntry());
1458 EXPECT_TRUE(controller.GetPendingEntry());
1459 EXPECT_FALSE(controller.CanGoBack());
1460 EXPECT_TRUE(controller.CanGoForward());
1462 main_test_rfh()->SendNavigate(2, url3);
1463 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1464 navigation_entry_committed_counter_ = 0;
1466 // The back navigation resulted in a completely new navigation.
1467 // TODO(darin): perhaps this behavior will be confusing to users?
1468 EXPECT_EQ(controller.GetEntryCount(), 3);
1469 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
1470 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1471 EXPECT_TRUE(controller.GetLastCommittedEntry());
1472 EXPECT_FALSE(controller.GetPendingEntry());
1473 EXPECT_TRUE(controller.CanGoBack());
1474 EXPECT_FALSE(controller.CanGoForward());
1477 // Receives a back message when there is a new pending navigation entry.
1478 TEST_F(NavigationControllerTest, Back_NewPending) {
1479 NavigationControllerImpl& controller = controller_impl();
1480 TestNotificationTracker notifications;
1481 RegisterForAllNavNotifications(&notifications, &controller);
1483 const GURL kUrl1("http://foo1");
1484 const GURL kUrl2("http://foo2");
1485 const GURL kUrl3("http://foo3");
1487 // First navigate two places so we have some back history.
1488 main_test_rfh()->SendNavigate(0, kUrl1);
1489 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1490 navigation_entry_committed_counter_ = 0;
1492 // controller.LoadURL(kUrl2, PAGE_TRANSITION_TYPED);
1493 main_test_rfh()->SendNavigate(1, kUrl2);
1494 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1495 navigation_entry_committed_counter_ = 0;
1497 // Now start a new pending navigation and go back before it commits.
1498 controller.LoadURL(kUrl3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1499 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1500 EXPECT_EQ(kUrl3, controller.GetPendingEntry()->GetURL());
1501 controller.GoBack();
1503 // The pending navigation should now be the "back" item and the new one
1504 // should be gone.
1505 EXPECT_EQ(0, controller.GetPendingEntryIndex());
1506 EXPECT_EQ(kUrl1, controller.GetPendingEntry()->GetURL());
1509 // Receives a back message when there is a different renavigation already
1510 // pending.
1511 TEST_F(NavigationControllerTest, Back_OtherBackPending) {
1512 NavigationControllerImpl& controller = controller_impl();
1513 const GURL kUrl1("http://foo/1");
1514 const GURL kUrl2("http://foo/2");
1515 const GURL kUrl3("http://foo/3");
1517 // First navigate three places so we have some back history.
1518 main_test_rfh()->SendNavigate(0, kUrl1);
1519 main_test_rfh()->SendNavigate(1, kUrl2);
1520 main_test_rfh()->SendNavigate(2, kUrl3);
1522 // With nothing pending, say we get a navigation to the second entry.
1523 main_test_rfh()->SendNavigate(1, kUrl2);
1525 // We know all the entries have the same site instance, so we can just grab
1526 // a random one for looking up other entries.
1527 SiteInstance* site_instance =
1528 NavigationEntryImpl::FromNavigationEntry(
1529 controller.GetLastCommittedEntry())->site_instance();
1531 // That second URL should be the last committed and it should have gotten the
1532 // new title.
1533 EXPECT_EQ(kUrl2, controller.GetEntryWithPageID(site_instance, 1)->GetURL());
1534 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
1535 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1537 // Now go forward to the last item again and say it was committed.
1538 controller.GoForward();
1539 main_test_rfh()->SendNavigate(2, kUrl3);
1541 // Now start going back one to the second page. It will be pending.
1542 controller.GoBack();
1543 EXPECT_EQ(1, controller.GetPendingEntryIndex());
1544 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
1546 // Not synthesize a totally new back event to the first page. This will not
1547 // match the pending one.
1548 main_test_rfh()->SendNavigate(0, kUrl1);
1550 // The committed navigation should clear the pending entry.
1551 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1553 // But the navigated entry should be the last committed.
1554 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
1555 EXPECT_EQ(kUrl1, controller.GetLastCommittedEntry()->GetURL());
1558 // Tests what happens when we navigate forward successfully.
1559 TEST_F(NavigationControllerTest, Forward) {
1560 NavigationControllerImpl& controller = controller_impl();
1561 TestNotificationTracker notifications;
1562 RegisterForAllNavNotifications(&notifications, &controller);
1564 const GURL url1("http://foo1");
1565 const GURL url2("http://foo2");
1567 main_test_rfh()->SendNavigate(0, url1);
1568 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1569 navigation_entry_committed_counter_ = 0;
1571 main_test_rfh()->SendNavigate(1, url2);
1572 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1573 navigation_entry_committed_counter_ = 0;
1575 controller.GoBack();
1576 main_test_rfh()->SendNavigate(0, url1);
1577 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1578 navigation_entry_committed_counter_ = 0;
1580 controller.GoForward();
1582 // We should now have a pending navigation to go forward.
1583 EXPECT_EQ(controller.GetEntryCount(), 2);
1584 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1585 EXPECT_EQ(controller.GetPendingEntryIndex(), 1);
1586 EXPECT_TRUE(controller.GetLastCommittedEntry());
1587 EXPECT_TRUE(controller.GetPendingEntry());
1588 EXPECT_TRUE(controller.CanGoBack());
1589 EXPECT_TRUE(controller.CanGoToOffset(-1));
1590 EXPECT_FALSE(controller.CanGoToOffset(-2)); // Cannot go back 2 steps.
1591 EXPECT_FALSE(controller.CanGoForward());
1592 EXPECT_FALSE(controller.CanGoToOffset(1));
1594 // Timestamp for entry 0 should be on or after that of entry 1
1595 // (since we went back to it).
1596 EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null());
1597 EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(),
1598 controller.GetEntryAtIndex(1)->GetTimestamp());
1600 main_test_rfh()->SendNavigate(1, url2);
1601 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1602 navigation_entry_committed_counter_ = 0;
1604 // The forward navigation completed successfully.
1605 EXPECT_EQ(controller.GetEntryCount(), 2);
1606 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1607 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1608 EXPECT_TRUE(controller.GetLastCommittedEntry());
1609 EXPECT_FALSE(controller.GetPendingEntry());
1610 EXPECT_TRUE(controller.CanGoBack());
1611 EXPECT_TRUE(controller.CanGoToOffset(-1));
1612 EXPECT_FALSE(controller.CanGoToOffset(-2)); // Cannot go back 2 steps.
1613 EXPECT_FALSE(controller.CanGoForward());
1614 EXPECT_FALSE(controller.CanGoToOffset(1));
1616 // Timestamp for entry 1 should be on or after that of entry 0
1617 // (since we went forward to it).
1618 EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(),
1619 controller.GetEntryAtIndex(0)->GetTimestamp());
1622 // Tests what happens when a forward navigation produces a new page.
1623 TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
1624 NavigationControllerImpl& controller = controller_impl();
1625 TestNotificationTracker notifications;
1626 RegisterForAllNavNotifications(&notifications, &controller);
1628 const GURL url1("http://foo1");
1629 const GURL url2("http://foo2");
1630 const GURL url3("http://foo3");
1632 main_test_rfh()->SendNavigate(0, url1);
1633 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1634 navigation_entry_committed_counter_ = 0;
1635 main_test_rfh()->SendNavigate(1, url2);
1636 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1637 navigation_entry_committed_counter_ = 0;
1639 controller.GoBack();
1640 main_test_rfh()->SendNavigate(0, url1);
1641 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1642 navigation_entry_committed_counter_ = 0;
1644 controller.GoForward();
1645 EXPECT_EQ(0U, notifications.size());
1647 // Should now have a pending navigation to go forward.
1648 EXPECT_EQ(controller.GetEntryCount(), 2);
1649 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1650 EXPECT_EQ(controller.GetPendingEntryIndex(), 1);
1651 EXPECT_TRUE(controller.GetLastCommittedEntry());
1652 EXPECT_TRUE(controller.GetPendingEntry());
1653 EXPECT_TRUE(controller.CanGoBack());
1654 EXPECT_FALSE(controller.CanGoForward());
1656 main_test_rfh()->SendNavigate(2, url3);
1657 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1658 navigation_entry_committed_counter_ = 0;
1659 EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_LIST_PRUNED));
1661 EXPECT_EQ(controller.GetEntryCount(), 2);
1662 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1663 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1664 EXPECT_TRUE(controller.GetLastCommittedEntry());
1665 EXPECT_FALSE(controller.GetPendingEntry());
1666 EXPECT_TRUE(controller.CanGoBack());
1667 EXPECT_FALSE(controller.CanGoForward());
1670 // Two consequent navigation for the same URL entered in should be considered
1671 // as SAME_PAGE navigation even when we are redirected to some other page.
1672 TEST_F(NavigationControllerTest, Redirect) {
1673 NavigationControllerImpl& controller = controller_impl();
1674 TestNotificationTracker notifications;
1675 RegisterForAllNavNotifications(&notifications, &controller);
1677 const GURL url1("http://foo1");
1678 const GURL url2("http://foo2"); // Redirection target
1680 // First request
1681 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1683 EXPECT_EQ(0U, notifications.size());
1684 main_test_rfh()->SendNavigate(0, url2);
1685 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1686 navigation_entry_committed_counter_ = 0;
1688 // Second request
1689 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1691 EXPECT_TRUE(controller.GetPendingEntry());
1692 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1693 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
1695 FrameHostMsg_DidCommitProvisionalLoad_Params params;
1696 params.page_id = 0;
1697 params.url = url2;
1698 params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
1699 params.redirects.push_back(GURL("http://foo1"));
1700 params.redirects.push_back(GURL("http://foo2"));
1701 params.should_update_history = false;
1702 params.gesture = NavigationGestureAuto;
1703 params.is_post = false;
1704 params.page_state = PageState::CreateFromURL(url2);
1706 LoadCommittedDetails details;
1708 EXPECT_EQ(0U, notifications.size());
1709 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
1710 &details));
1711 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1712 navigation_entry_committed_counter_ = 0;
1714 EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE);
1715 EXPECT_EQ(controller.GetEntryCount(), 1);
1716 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1717 EXPECT_TRUE(controller.GetLastCommittedEntry());
1718 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1719 EXPECT_FALSE(controller.GetPendingEntry());
1720 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
1722 EXPECT_FALSE(controller.CanGoBack());
1723 EXPECT_FALSE(controller.CanGoForward());
1726 // Similar to Redirect above, but the first URL is requested by POST,
1727 // the second URL is requested by GET. NavigationEntry::has_post_data_
1728 // must be cleared. http://crbug.com/21245
1729 TEST_F(NavigationControllerTest, PostThenRedirect) {
1730 NavigationControllerImpl& controller = controller_impl();
1731 TestNotificationTracker notifications;
1732 RegisterForAllNavNotifications(&notifications, &controller);
1734 const GURL url1("http://foo1");
1735 const GURL url2("http://foo2"); // Redirection target
1737 // First request as POST
1738 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1739 controller.GetVisibleEntry()->SetHasPostData(true);
1741 EXPECT_EQ(0U, notifications.size());
1742 main_test_rfh()->SendNavigate(0, url2);
1743 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1744 navigation_entry_committed_counter_ = 0;
1746 // Second request
1747 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1749 EXPECT_TRUE(controller.GetPendingEntry());
1750 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1751 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
1753 FrameHostMsg_DidCommitProvisionalLoad_Params params;
1754 params.page_id = 0;
1755 params.url = url2;
1756 params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
1757 params.redirects.push_back(GURL("http://foo1"));
1758 params.redirects.push_back(GURL("http://foo2"));
1759 params.should_update_history = false;
1760 params.gesture = NavigationGestureAuto;
1761 params.is_post = false;
1762 params.page_state = PageState::CreateFromURL(url2);
1764 LoadCommittedDetails details;
1766 EXPECT_EQ(0U, notifications.size());
1767 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
1768 &details));
1769 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1770 navigation_entry_committed_counter_ = 0;
1772 EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE);
1773 EXPECT_EQ(controller.GetEntryCount(), 1);
1774 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1775 EXPECT_TRUE(controller.GetLastCommittedEntry());
1776 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1777 EXPECT_FALSE(controller.GetPendingEntry());
1778 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
1779 EXPECT_FALSE(controller.GetVisibleEntry()->GetHasPostData());
1781 EXPECT_FALSE(controller.CanGoBack());
1782 EXPECT_FALSE(controller.CanGoForward());
1785 // A redirect right off the bat should be a NEW_PAGE.
1786 TEST_F(NavigationControllerTest, ImmediateRedirect) {
1787 NavigationControllerImpl& controller = controller_impl();
1788 TestNotificationTracker notifications;
1789 RegisterForAllNavNotifications(&notifications, &controller);
1791 const GURL url1("http://foo1");
1792 const GURL url2("http://foo2"); // Redirection target
1794 // First request
1795 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1797 EXPECT_TRUE(controller.GetPendingEntry());
1798 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1799 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
1801 FrameHostMsg_DidCommitProvisionalLoad_Params params;
1802 params.page_id = 0;
1803 params.url = url2;
1804 params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
1805 params.redirects.push_back(GURL("http://foo1"));
1806 params.redirects.push_back(GURL("http://foo2"));
1807 params.should_update_history = false;
1808 params.gesture = NavigationGestureAuto;
1809 params.is_post = false;
1810 params.page_state = PageState::CreateFromURL(url2);
1812 LoadCommittedDetails details;
1814 EXPECT_EQ(0U, notifications.size());
1815 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
1816 &details));
1817 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1818 navigation_entry_committed_counter_ = 0;
1820 EXPECT_TRUE(details.type == NAVIGATION_TYPE_NEW_PAGE);
1821 EXPECT_EQ(controller.GetEntryCount(), 1);
1822 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1823 EXPECT_TRUE(controller.GetLastCommittedEntry());
1824 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1825 EXPECT_FALSE(controller.GetPendingEntry());
1826 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
1828 EXPECT_FALSE(controller.CanGoBack());
1829 EXPECT_FALSE(controller.CanGoForward());
1832 // Tests navigation via link click within a subframe. A new navigation entry
1833 // should be created.
1834 TEST_F(NavigationControllerTest, NewSubframe) {
1835 NavigationControllerImpl& controller = controller_impl();
1836 TestNotificationTracker notifications;
1837 RegisterForAllNavNotifications(&notifications, &controller);
1839 const GURL url1("http://foo1");
1840 main_test_rfh()->SendNavigate(0, url1);
1841 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1842 navigation_entry_committed_counter_ = 0;
1844 const GURL url2("http://foo2");
1845 FrameHostMsg_DidCommitProvisionalLoad_Params params;
1846 params.page_id = 1;
1847 params.url = url2;
1848 params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
1849 params.should_update_history = false;
1850 params.gesture = NavigationGestureUser;
1851 params.is_post = false;
1852 params.page_state = PageState::CreateFromURL(url2);
1854 LoadCommittedDetails details;
1855 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
1856 &details));
1857 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1858 navigation_entry_committed_counter_ = 0;
1859 EXPECT_EQ(url1, details.previous_url);
1860 EXPECT_FALSE(details.is_in_page);
1861 EXPECT_FALSE(details.is_main_frame);
1863 // The new entry should be appended.
1864 EXPECT_EQ(2, controller.GetEntryCount());
1866 // New entry should refer to the new page, but the old URL (entries only
1867 // reflect the toplevel URL).
1868 EXPECT_EQ(url1, details.entry->GetURL());
1869 EXPECT_EQ(params.page_id, details.entry->GetPageID());
1872 // Some pages create a popup, then write an iframe into it. This causes a
1873 // subframe navigation without having any committed entry. Such navigations
1874 // just get thrown on the ground, but we shouldn't crash.
1875 TEST_F(NavigationControllerTest, SubframeOnEmptyPage) {
1876 NavigationControllerImpl& controller = controller_impl();
1877 TestNotificationTracker notifications;
1878 RegisterForAllNavNotifications(&notifications, &controller);
1880 // Navigation controller currently has no entries.
1881 const GURL url("http://foo2");
1882 FrameHostMsg_DidCommitProvisionalLoad_Params params;
1883 params.page_id = 1;
1884 params.url = url;
1885 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
1886 params.should_update_history = false;
1887 params.gesture = NavigationGestureAuto;
1888 params.is_post = false;
1889 params.page_state = PageState::CreateFromURL(url);
1891 LoadCommittedDetails details;
1892 EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params,
1893 &details));
1894 EXPECT_EQ(0U, notifications.size());
1897 // Auto subframes are ones the page loads automatically like ads. They should
1898 // not create new navigation entries.
1899 TEST_F(NavigationControllerTest, AutoSubframe) {
1900 NavigationControllerImpl& controller = controller_impl();
1901 TestNotificationTracker notifications;
1902 RegisterForAllNavNotifications(&notifications, &controller);
1904 const GURL url1("http://foo1");
1905 main_test_rfh()->SendNavigate(0, url1);
1906 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1907 navigation_entry_committed_counter_ = 0;
1909 const GURL url2("http://foo2");
1910 FrameHostMsg_DidCommitProvisionalLoad_Params params;
1911 params.page_id = 0;
1912 params.url = url2;
1913 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
1914 params.should_update_history = false;
1915 params.gesture = NavigationGestureUser;
1916 params.is_post = false;
1917 params.page_state = PageState::CreateFromURL(url2);
1919 // Navigating should do nothing.
1920 LoadCommittedDetails details;
1921 EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params,
1922 &details));
1923 EXPECT_EQ(0U, notifications.size());
1925 // There should still be only one entry.
1926 EXPECT_EQ(1, controller.GetEntryCount());
1929 // Tests navigation and then going back to a subframe navigation.
1930 TEST_F(NavigationControllerTest, BackSubframe) {
1931 NavigationControllerImpl& controller = controller_impl();
1932 TestNotificationTracker notifications;
1933 RegisterForAllNavNotifications(&notifications, &controller);
1935 // Main page.
1936 const GURL url1("http://foo1");
1937 main_test_rfh()->SendNavigate(0, url1);
1938 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1939 navigation_entry_committed_counter_ = 0;
1941 // First manual subframe navigation.
1942 const GURL url2("http://foo2");
1943 FrameHostMsg_DidCommitProvisionalLoad_Params params;
1944 params.page_id = 1;
1945 params.url = url2;
1946 params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
1947 params.should_update_history = false;
1948 params.gesture = NavigationGestureUser;
1949 params.is_post = false;
1950 params.page_state = PageState::CreateFromURL(url2);
1952 // This should generate a new entry.
1953 LoadCommittedDetails details;
1954 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
1955 &details));
1956 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1957 navigation_entry_committed_counter_ = 0;
1958 EXPECT_EQ(2, controller.GetEntryCount());
1960 // Second manual subframe navigation should also make a new entry.
1961 const GURL url3("http://foo3");
1962 params.page_id = 2;
1963 params.url = url3;
1964 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
1965 &details));
1966 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1967 navigation_entry_committed_counter_ = 0;
1968 EXPECT_EQ(3, controller.GetEntryCount());
1969 EXPECT_EQ(2, controller.GetCurrentEntryIndex());
1971 // Go back one.
1972 controller.GoBack();
1973 params.url = url2;
1974 params.page_id = 1;
1975 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
1976 &details));
1977 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1978 navigation_entry_committed_counter_ = 0;
1979 EXPECT_EQ(3, controller.GetEntryCount());
1980 EXPECT_EQ(1, controller.GetCurrentEntryIndex());
1981 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1982 EXPECT_FALSE(controller.GetPendingEntry());
1984 // Go back one more.
1985 controller.GoBack();
1986 params.url = url1;
1987 params.page_id = 0;
1988 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
1989 &details));
1990 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1991 navigation_entry_committed_counter_ = 0;
1992 EXPECT_EQ(3, controller.GetEntryCount());
1993 EXPECT_EQ(0, controller.GetCurrentEntryIndex());
1994 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1995 EXPECT_FALSE(controller.GetPendingEntry());
1998 TEST_F(NavigationControllerTest, LinkClick) {
1999 NavigationControllerImpl& controller = controller_impl();
2000 TestNotificationTracker notifications;
2001 RegisterForAllNavNotifications(&notifications, &controller);
2003 const GURL url1("http://foo1");
2004 const GURL url2("http://foo2");
2006 main_test_rfh()->SendNavigate(0, url1);
2007 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2008 navigation_entry_committed_counter_ = 0;
2010 main_test_rfh()->SendNavigate(1, url2);
2011 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2012 navigation_entry_committed_counter_ = 0;
2014 // Should not have produced a new session history entry.
2015 EXPECT_EQ(controller.GetEntryCount(), 2);
2016 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
2017 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
2018 EXPECT_TRUE(controller.GetLastCommittedEntry());
2019 EXPECT_FALSE(controller.GetPendingEntry());
2020 EXPECT_TRUE(controller.CanGoBack());
2021 EXPECT_FALSE(controller.CanGoForward());
2024 TEST_F(NavigationControllerTest, InPage) {
2025 NavigationControllerImpl& controller = controller_impl();
2026 TestNotificationTracker notifications;
2027 RegisterForAllNavNotifications(&notifications, &controller);
2029 // Main page.
2030 const GURL url1("http://foo");
2031 main_test_rfh()->SendNavigate(0, url1);
2032 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2033 navigation_entry_committed_counter_ = 0;
2035 // Ensure main page navigation to same url respects the was_within_same_page
2036 // hint provided in the params.
2037 FrameHostMsg_DidCommitProvisionalLoad_Params self_params;
2038 self_params.page_id = 0;
2039 self_params.url = url1;
2040 self_params.transition = PAGE_TRANSITION_LINK;
2041 self_params.should_update_history = false;
2042 self_params.gesture = NavigationGestureUser;
2043 self_params.is_post = false;
2044 self_params.page_state = PageState::CreateFromURL(url1);
2045 self_params.was_within_same_page = true;
2047 LoadCommittedDetails details;
2048 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), self_params,
2049 &details));
2050 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2051 navigation_entry_committed_counter_ = 0;
2052 EXPECT_TRUE(details.is_in_page);
2053 EXPECT_TRUE(details.did_replace_entry);
2054 EXPECT_EQ(1, controller.GetEntryCount());
2056 // Fragment navigation to a new page_id.
2057 const GURL url2("http://foo#a");
2058 FrameHostMsg_DidCommitProvisionalLoad_Params params;
2059 params.page_id = 1;
2060 params.url = url2;
2061 params.transition = PAGE_TRANSITION_LINK;
2062 params.should_update_history = false;
2063 params.gesture = NavigationGestureUser;
2064 params.is_post = false;
2065 params.page_state = PageState::CreateFromURL(url2);
2066 params.was_within_same_page = true;
2068 // This should generate a new entry.
2069 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
2070 &details));
2071 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2072 navigation_entry_committed_counter_ = 0;
2073 EXPECT_TRUE(details.is_in_page);
2074 EXPECT_FALSE(details.did_replace_entry);
2075 EXPECT_EQ(2, controller.GetEntryCount());
2077 // Go back one.
2078 FrameHostMsg_DidCommitProvisionalLoad_Params back_params(params);
2079 controller.GoBack();
2080 back_params.url = url1;
2081 back_params.page_id = 0;
2082 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), back_params,
2083 &details));
2084 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2085 navigation_entry_committed_counter_ = 0;
2086 EXPECT_TRUE(details.is_in_page);
2087 EXPECT_EQ(2, controller.GetEntryCount());
2088 EXPECT_EQ(0, controller.GetCurrentEntryIndex());
2089 EXPECT_EQ(back_params.url, controller.GetVisibleEntry()->GetURL());
2091 // Go forward
2092 FrameHostMsg_DidCommitProvisionalLoad_Params forward_params(params);
2093 controller.GoForward();
2094 forward_params.url = url2;
2095 forward_params.page_id = 1;
2096 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), forward_params,
2097 &details));
2098 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2099 navigation_entry_committed_counter_ = 0;
2100 EXPECT_TRUE(details.is_in_page);
2101 EXPECT_EQ(2, controller.GetEntryCount());
2102 EXPECT_EQ(1, controller.GetCurrentEntryIndex());
2103 EXPECT_EQ(forward_params.url,
2104 controller.GetVisibleEntry()->GetURL());
2106 // Now go back and forward again. This is to work around a bug where we would
2107 // compare the incoming URL with the last committed entry rather than the
2108 // one identified by an existing page ID. This would result in the second URL
2109 // losing the reference fragment when you navigate away from it and then back.
2110 controller.GoBack();
2111 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), back_params,
2112 &details));
2113 controller.GoForward();
2114 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), forward_params,
2115 &details));
2116 EXPECT_EQ(forward_params.url,
2117 controller.GetVisibleEntry()->GetURL());
2119 // Finally, navigate to an unrelated URL to make sure in_page is not sticky.
2120 const GURL url3("http://bar");
2121 params.page_id = 2;
2122 params.url = url3;
2123 navigation_entry_committed_counter_ = 0;
2124 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
2125 &details));
2126 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2127 navigation_entry_committed_counter_ = 0;
2128 EXPECT_FALSE(details.is_in_page);
2129 EXPECT_EQ(3, controller.GetEntryCount());
2130 EXPECT_EQ(2, controller.GetCurrentEntryIndex());
2133 TEST_F(NavigationControllerTest, InPage_Replace) {
2134 NavigationControllerImpl& controller = controller_impl();
2135 TestNotificationTracker notifications;
2136 RegisterForAllNavNotifications(&notifications, &controller);
2138 // Main page.
2139 const GURL url1("http://foo");
2140 main_test_rfh()->SendNavigate(0, url1);
2141 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2142 navigation_entry_committed_counter_ = 0;
2144 // First navigation.
2145 const GURL url2("http://foo#a");
2146 FrameHostMsg_DidCommitProvisionalLoad_Params params;
2147 params.page_id = 0; // Same page_id
2148 params.url = url2;
2149 params.transition = PAGE_TRANSITION_LINK;
2150 params.should_update_history = false;
2151 params.gesture = NavigationGestureUser;
2152 params.is_post = false;
2153 params.page_state = PageState::CreateFromURL(url2);
2155 // This should NOT generate a new entry, nor prune the list.
2156 LoadCommittedDetails details;
2157 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
2158 &details));
2159 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2160 navigation_entry_committed_counter_ = 0;
2161 EXPECT_TRUE(details.is_in_page);
2162 EXPECT_TRUE(details.did_replace_entry);
2163 EXPECT_EQ(1, controller.GetEntryCount());
2166 // Tests for http://crbug.com/40395
2167 // Simulates this:
2168 // <script>
2169 // window.location.replace("#a");
2170 // window.location='http://foo3/';
2171 // </script>
2172 TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
2173 NavigationControllerImpl& controller = controller_impl();
2174 TestNotificationTracker notifications;
2175 RegisterForAllNavNotifications(&notifications, &controller);
2177 // Load an initial page.
2179 const GURL url("http://foo/");
2180 main_test_rfh()->SendNavigate(0, url);
2181 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2182 navigation_entry_committed_counter_ = 0;
2185 // Navigate to a new page.
2187 const GURL url("http://foo2/");
2188 main_test_rfh()->SendNavigate(1, url);
2189 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2190 navigation_entry_committed_counter_ = 0;
2193 // Navigate within the page.
2195 const GURL url("http://foo2/#a");
2196 FrameHostMsg_DidCommitProvisionalLoad_Params params;
2197 params.page_id = 1; // Same page_id
2198 params.url = url;
2199 params.transition = PAGE_TRANSITION_LINK;
2200 params.redirects.push_back(url);
2201 params.should_update_history = true;
2202 params.gesture = NavigationGestureUnknown;
2203 params.is_post = false;
2204 params.page_state = PageState::CreateFromURL(url);
2206 // This should NOT generate a new entry, nor prune the list.
2207 LoadCommittedDetails details;
2208 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
2209 &details));
2210 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2211 navigation_entry_committed_counter_ = 0;
2212 EXPECT_TRUE(details.is_in_page);
2213 EXPECT_TRUE(details.did_replace_entry);
2214 EXPECT_EQ(2, controller.GetEntryCount());
2217 // Perform a client redirect to a new page.
2219 const GURL url("http://foo3/");
2220 FrameHostMsg_DidCommitProvisionalLoad_Params params;
2221 params.page_id = 2; // New page_id
2222 params.url = url;
2223 params.transition = PAGE_TRANSITION_CLIENT_REDIRECT;
2224 params.redirects.push_back(GURL("http://foo2/#a"));
2225 params.redirects.push_back(url);
2226 params.should_update_history = true;
2227 params.gesture = NavigationGestureUnknown;
2228 params.is_post = false;
2229 params.page_state = PageState::CreateFromURL(url);
2231 // This SHOULD generate a new entry.
2232 LoadCommittedDetails details;
2233 EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
2234 &details));
2235 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2236 navigation_entry_committed_counter_ = 0;
2237 EXPECT_FALSE(details.is_in_page);
2238 EXPECT_EQ(3, controller.GetEntryCount());
2241 // Verify that BACK brings us back to http://foo2/.
2243 const GURL url("http://foo2/");
2244 controller.GoBack();
2245 main_test_rfh()->SendNavigate(1, url);
2246 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2247 navigation_entry_committed_counter_ = 0;
2248 EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
2252 // NotificationObserver implementation used in verifying we've received the
2253 // NOTIFICATION_NAV_LIST_PRUNED method.
2254 class PrunedListener : public NotificationObserver {
2255 public:
2256 explicit PrunedListener(NavigationControllerImpl* controller)
2257 : notification_count_(0) {
2258 registrar_.Add(this, NOTIFICATION_NAV_LIST_PRUNED,
2259 Source<NavigationController>(controller));
2262 virtual void Observe(int type,
2263 const NotificationSource& source,
2264 const NotificationDetails& details) OVERRIDE {
2265 if (type == NOTIFICATION_NAV_LIST_PRUNED) {
2266 notification_count_++;
2267 details_ = *(Details<PrunedDetails>(details).ptr());
2271 // Number of times NAV_LIST_PRUNED has been observed.
2272 int notification_count_;
2274 // Details from the last NAV_LIST_PRUNED.
2275 PrunedDetails details_;
2277 private:
2278 NotificationRegistrar registrar_;
2280 DISALLOW_COPY_AND_ASSIGN(PrunedListener);
2283 // Tests that we limit the number of navigation entries created correctly.
2284 TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
2285 NavigationControllerImpl& controller = controller_impl();
2286 size_t original_count = NavigationControllerImpl::max_entry_count();
2287 const int kMaxEntryCount = 5;
2289 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
2291 int url_index;
2292 // Load up to the max count, all entries should be there.
2293 for (url_index = 0; url_index < kMaxEntryCount; url_index++) {
2294 GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
2295 controller.LoadURL(
2296 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2297 main_test_rfh()->SendNavigate(url_index, url);
2300 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
2302 // Created a PrunedListener to observe prune notifications.
2303 PrunedListener listener(&controller);
2305 // Navigate some more.
2306 GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
2307 controller.LoadURL(
2308 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2309 main_test_rfh()->SendNavigate(url_index, url);
2310 url_index++;
2312 // We should have got a pruned navigation.
2313 EXPECT_EQ(1, listener.notification_count_);
2314 EXPECT_TRUE(listener.details_.from_front);
2315 EXPECT_EQ(1, listener.details_.count);
2317 // We expect http://www.a.com/0 to be gone.
2318 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
2319 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
2320 GURL("http:////www.a.com/1"));
2322 // More navigations.
2323 for (int i = 0; i < 3; i++) {
2324 url = GURL(base::StringPrintf("http:////www.a.com/%d", url_index));
2325 controller.LoadURL(
2326 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2327 main_test_rfh()->SendNavigate(url_index, url);
2328 url_index++;
2330 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
2331 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
2332 GURL("http:////www.a.com/4"));
2334 NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
2337 // Tests that we can do a restore and navigate to the restored entries and
2338 // everything is updated properly. This can be tricky since there is no
2339 // SiteInstance for the entries created initially.
2340 TEST_F(NavigationControllerTest, RestoreNavigate) {
2341 // Create a NavigationController with a restored set of tabs.
2342 GURL url("http://foo");
2343 std::vector<NavigationEntry*> entries;
2344 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
2345 url, Referrer(), PAGE_TRANSITION_RELOAD, false, std::string(),
2346 browser_context());
2347 entry->SetPageID(0);
2348 entry->SetTitle(base::ASCIIToUTF16("Title"));
2349 entry->SetPageState(PageState::CreateFromEncodedData("state"));
2350 const base::Time timestamp = base::Time::Now();
2351 entry->SetTimestamp(timestamp);
2352 entries.push_back(entry);
2353 scoped_ptr<WebContentsImpl> our_contents(static_cast<WebContentsImpl*>(
2354 WebContents::Create(WebContents::CreateParams(browser_context()))));
2355 NavigationControllerImpl& our_controller = our_contents->GetController();
2356 our_controller.Restore(
2358 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
2359 &entries);
2360 ASSERT_EQ(0u, entries.size());
2362 // Before navigating to the restored entry, it should have a restore_type
2363 // and no SiteInstance.
2364 ASSERT_EQ(1, our_controller.GetEntryCount());
2365 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
2366 NavigationEntryImpl::FromNavigationEntry(
2367 our_controller.GetEntryAtIndex(0))->restore_type());
2368 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
2369 our_controller.GetEntryAtIndex(0))->site_instance());
2371 // After navigating, we should have one entry, and it should be "pending".
2372 // It should now have a SiteInstance and no restore_type.
2373 our_controller.GoToIndex(0);
2374 EXPECT_EQ(1, our_controller.GetEntryCount());
2375 EXPECT_EQ(our_controller.GetEntryAtIndex(0),
2376 our_controller.GetPendingEntry());
2377 EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
2378 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
2379 NavigationEntryImpl::FromNavigationEntry
2380 (our_controller.GetEntryAtIndex(0))->restore_type());
2381 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
2382 our_controller.GetEntryAtIndex(0))->site_instance());
2384 // Timestamp should remain the same before the navigation finishes.
2385 EXPECT_EQ(timestamp, our_controller.GetEntryAtIndex(0)->GetTimestamp());
2387 // Say we navigated to that entry.
2388 FrameHostMsg_DidCommitProvisionalLoad_Params params;
2389 params.page_id = 0;
2390 params.url = url;
2391 params.transition = PAGE_TRANSITION_LINK;
2392 params.should_update_history = false;
2393 params.gesture = NavigationGestureUser;
2394 params.is_post = false;
2395 params.page_state = PageState::CreateFromURL(url);
2396 LoadCommittedDetails details;
2397 our_controller.RendererDidNavigate(our_contents->GetMainFrame(), params,
2398 &details);
2400 // There should be no longer any pending entry and one committed one. This
2401 // means that we were able to locate the entry, assign its site instance, and
2402 // commit it properly.
2403 EXPECT_EQ(1, our_controller.GetEntryCount());
2404 EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
2405 EXPECT_FALSE(our_controller.GetPendingEntry());
2406 EXPECT_EQ(url,
2407 NavigationEntryImpl::FromNavigationEntry(
2408 our_controller.GetLastCommittedEntry())->site_instance()->
2409 GetSiteURL());
2410 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
2411 NavigationEntryImpl::FromNavigationEntry(
2412 our_controller.GetEntryAtIndex(0))->restore_type());
2414 // Timestamp should have been updated.
2415 EXPECT_GE(our_controller.GetEntryAtIndex(0)->GetTimestamp(), timestamp);
2418 // Tests that we can still navigate to a restored entry after a different
2419 // navigation fails and clears the pending entry. http://crbug.com/90085
2420 TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
2421 // Create a NavigationController with a restored set of tabs.
2422 GURL url("http://foo");
2423 std::vector<NavigationEntry*> entries;
2424 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
2425 url, Referrer(), PAGE_TRANSITION_RELOAD, false, std::string(),
2426 browser_context());
2427 entry->SetPageID(0);
2428 entry->SetTitle(base::ASCIIToUTF16("Title"));
2429 entry->SetPageState(PageState::CreateFromEncodedData("state"));
2430 entries.push_back(entry);
2431 scoped_ptr<WebContentsImpl> our_contents(static_cast<WebContentsImpl*>(
2432 WebContents::Create(WebContents::CreateParams(browser_context()))));
2433 NavigationControllerImpl& our_controller = our_contents->GetController();
2434 our_controller.Restore(
2435 0, NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY, &entries);
2436 ASSERT_EQ(0u, entries.size());
2438 // Before navigating to the restored entry, it should have a restore_type
2439 // and no SiteInstance.
2440 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
2441 NavigationEntryImpl::FromNavigationEntry(
2442 our_controller.GetEntryAtIndex(0))->restore_type());
2443 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
2444 our_controller.GetEntryAtIndex(0))->site_instance());
2446 // After navigating, we should have one entry, and it should be "pending".
2447 // It should now have a SiteInstance and no restore_type.
2448 our_controller.GoToIndex(0);
2449 EXPECT_EQ(1, our_controller.GetEntryCount());
2450 EXPECT_EQ(our_controller.GetEntryAtIndex(0),
2451 our_controller.GetPendingEntry());
2452 EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
2453 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
2454 NavigationEntryImpl::FromNavigationEntry(
2455 our_controller.GetEntryAtIndex(0))->restore_type());
2456 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
2457 our_controller.GetEntryAtIndex(0))->site_instance());
2459 // This pending navigation may have caused a different navigation to fail,
2460 // which causes the pending entry to be cleared.
2461 FrameHostMsg_DidFailProvisionalLoadWithError_Params fail_load_params;
2462 fail_load_params.error_code = net::ERR_ABORTED;
2463 fail_load_params.error_description = base::string16();
2464 fail_load_params.url = url;
2465 fail_load_params.showing_repost_interstitial = false;
2466 main_test_rfh()->OnMessageReceived(
2467 FrameHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
2468 fail_load_params));
2470 // Now the pending restored entry commits.
2471 FrameHostMsg_DidCommitProvisionalLoad_Params params;
2472 params.page_id = 0;
2473 params.url = url;
2474 params.transition = PAGE_TRANSITION_LINK;
2475 params.should_update_history = false;
2476 params.gesture = NavigationGestureUser;
2477 params.is_post = false;
2478 params.page_state = PageState::CreateFromURL(url);
2479 LoadCommittedDetails details;
2480 our_controller.RendererDidNavigate(our_contents->GetMainFrame(), params,
2481 &details);
2483 // There should be no pending entry and one committed one.
2484 EXPECT_EQ(1, our_controller.GetEntryCount());
2485 EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
2486 EXPECT_FALSE(our_controller.GetPendingEntry());
2487 EXPECT_EQ(url,
2488 NavigationEntryImpl::FromNavigationEntry(
2489 our_controller.GetLastCommittedEntry())->site_instance()->
2490 GetSiteURL());
2491 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
2492 NavigationEntryImpl::FromNavigationEntry(
2493 our_controller.GetEntryAtIndex(0))->restore_type());
2496 // Make sure that the page type and stuff is correct after an interstitial.
2497 TEST_F(NavigationControllerTest, Interstitial) {
2498 NavigationControllerImpl& controller = controller_impl();
2499 // First navigate somewhere normal.
2500 const GURL url1("http://foo");
2501 controller.LoadURL(
2502 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2503 main_test_rfh()->SendNavigate(0, url1);
2505 // Now navigate somewhere with an interstitial.
2506 const GURL url2("http://bar");
2507 controller.LoadURL(
2508 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2509 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
2510 set_page_type(PAGE_TYPE_INTERSTITIAL);
2512 // At this point the interstitial will be displayed and the load will still
2513 // be pending. If the user continues, the load will commit.
2514 main_test_rfh()->SendNavigate(1, url2);
2516 // The page should be a normal page again.
2517 EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
2518 EXPECT_EQ(PAGE_TYPE_NORMAL,
2519 controller.GetLastCommittedEntry()->GetPageType());
2522 TEST_F(NavigationControllerTest, RemoveEntry) {
2523 NavigationControllerImpl& controller = controller_impl();
2524 const GURL url1("http://foo/1");
2525 const GURL url2("http://foo/2");
2526 const GURL url3("http://foo/3");
2527 const GURL url4("http://foo/4");
2528 const GURL url5("http://foo/5");
2529 const GURL pending_url("http://foo/pending");
2530 const GURL default_url("http://foo/default");
2532 controller.LoadURL(
2533 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2534 main_test_rfh()->SendNavigate(0, url1);
2535 controller.LoadURL(
2536 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2537 main_test_rfh()->SendNavigate(1, url2);
2538 controller.LoadURL(
2539 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2540 main_test_rfh()->SendNavigate(2, url3);
2541 controller.LoadURL(
2542 url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2543 main_test_rfh()->SendNavigate(3, url4);
2544 controller.LoadURL(
2545 url5, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2546 main_test_rfh()->SendNavigate(4, url5);
2548 // Try to remove the last entry. Will fail because it is the current entry.
2549 EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
2550 EXPECT_EQ(5, controller.GetEntryCount());
2551 EXPECT_EQ(4, controller.GetLastCommittedEntryIndex());
2553 // Go back, but don't commit yet. Check that we can't delete the current
2554 // and pending entries.
2555 controller.GoBack();
2556 EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
2557 EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 2));
2559 // Now commit and delete the last entry.
2560 main_test_rfh()->SendNavigate(3, url4);
2561 EXPECT_TRUE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
2562 EXPECT_EQ(4, controller.GetEntryCount());
2563 EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
2564 EXPECT_FALSE(controller.GetPendingEntry());
2566 // Remove an entry which is not the last committed one.
2567 EXPECT_TRUE(controller.RemoveEntryAtIndex(0));
2568 EXPECT_EQ(3, controller.GetEntryCount());
2569 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
2570 EXPECT_FALSE(controller.GetPendingEntry());
2572 // Remove the 2 remaining entries.
2573 controller.RemoveEntryAtIndex(1);
2574 controller.RemoveEntryAtIndex(0);
2576 // This should leave us with only the last committed entry.
2577 EXPECT_EQ(1, controller.GetEntryCount());
2578 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
2581 // Tests the transient entry, making sure it goes away with all navigations.
2582 TEST_F(NavigationControllerTest, TransientEntry) {
2583 NavigationControllerImpl& controller = controller_impl();
2584 TestNotificationTracker notifications;
2585 RegisterForAllNavNotifications(&notifications, &controller);
2587 const GURL url0("http://foo/0");
2588 const GURL url1("http://foo/1");
2589 const GURL url2("http://foo/2");
2590 const GURL url3("http://foo/3");
2591 const GURL url3_ref("http://foo/3#bar");
2592 const GURL url4("http://foo/4");
2593 const GURL transient_url("http://foo/transient");
2595 controller.LoadURL(
2596 url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2597 main_test_rfh()->SendNavigate(0, url0);
2598 controller.LoadURL(
2599 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2600 main_test_rfh()->SendNavigate(1, url1);
2602 notifications.Reset();
2604 // Adding a transient with no pending entry.
2605 NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
2606 transient_entry->SetURL(transient_url);
2607 controller.SetTransientEntry(transient_entry);
2609 // We should not have received any notifications.
2610 EXPECT_EQ(0U, notifications.size());
2612 // Check our state.
2613 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
2614 EXPECT_EQ(controller.GetEntryCount(), 3);
2615 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
2616 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
2617 EXPECT_TRUE(controller.GetLastCommittedEntry());
2618 EXPECT_FALSE(controller.GetPendingEntry());
2619 EXPECT_TRUE(controller.CanGoBack());
2620 EXPECT_FALSE(controller.CanGoForward());
2621 EXPECT_EQ(contents()->GetMaxPageID(), 1);
2623 // Navigate.
2624 controller.LoadURL(
2625 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2626 main_test_rfh()->SendNavigate(2, url2);
2628 // We should have navigated, transient entry should be gone.
2629 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
2630 EXPECT_EQ(controller.GetEntryCount(), 3);
2632 // Add a transient again, then navigate with no pending entry this time.
2633 transient_entry = new NavigationEntryImpl;
2634 transient_entry->SetURL(transient_url);
2635 controller.SetTransientEntry(transient_entry);
2636 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
2637 main_test_rfh()->SendNavigate(3, url3);
2638 // Transient entry should be gone.
2639 EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
2640 EXPECT_EQ(controller.GetEntryCount(), 4);
2642 // Initiate a navigation, add a transient then commit navigation.
2643 controller.LoadURL(
2644 url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2645 transient_entry = new NavigationEntryImpl;
2646 transient_entry->SetURL(transient_url);
2647 controller.SetTransientEntry(transient_entry);
2648 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
2649 main_test_rfh()->SendNavigate(4, url4);
2650 EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
2651 EXPECT_EQ(controller.GetEntryCount(), 5);
2653 // Add a transient and go back. This should simply remove the transient.
2654 transient_entry = new NavigationEntryImpl;
2655 transient_entry->SetURL(transient_url);
2656 controller.SetTransientEntry(transient_entry);
2657 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
2658 EXPECT_TRUE(controller.CanGoBack());
2659 EXPECT_FALSE(controller.CanGoForward());
2660 controller.GoBack();
2661 // Transient entry should be gone.
2662 EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
2663 EXPECT_EQ(controller.GetEntryCount(), 5);
2664 main_test_rfh()->SendNavigate(3, url3);
2666 // Add a transient and go to an entry before the current one.
2667 transient_entry = new NavigationEntryImpl;
2668 transient_entry->SetURL(transient_url);
2669 controller.SetTransientEntry(transient_entry);
2670 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
2671 controller.GoToIndex(1);
2672 // The navigation should have been initiated, transient entry should be gone.
2673 EXPECT_FALSE(controller.GetTransientEntry());
2674 EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
2675 // Visible entry does not update for history navigations until commit.
2676 EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
2677 main_test_rfh()->SendNavigate(1, url1);
2678 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
2680 // Add a transient and go to an entry after the current one.
2681 transient_entry = new NavigationEntryImpl;
2682 transient_entry->SetURL(transient_url);
2683 controller.SetTransientEntry(transient_entry);
2684 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
2685 controller.GoToIndex(3);
2686 // The navigation should have been initiated, transient entry should be gone.
2687 // Because of the transient entry that is removed, going to index 3 makes us
2688 // land on url2 (which is visible after the commit).
2689 EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL());
2690 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
2691 main_test_rfh()->SendNavigate(2, url2);
2692 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
2694 // Add a transient and go forward.
2695 transient_entry = new NavigationEntryImpl;
2696 transient_entry->SetURL(transient_url);
2697 controller.SetTransientEntry(transient_entry);
2698 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
2699 EXPECT_TRUE(controller.CanGoForward());
2700 controller.GoForward();
2701 // We should have navigated, transient entry should be gone.
2702 EXPECT_FALSE(controller.GetTransientEntry());
2703 EXPECT_EQ(url3, controller.GetPendingEntry()->GetURL());
2704 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
2705 main_test_rfh()->SendNavigate(3, url3);
2706 EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
2708 // Add a transient and do an in-page navigation, replacing the current entry.
2709 transient_entry = new NavigationEntryImpl;
2710 transient_entry->SetURL(transient_url);
2711 controller.SetTransientEntry(transient_entry);
2712 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
2713 main_test_rfh()->SendNavigate(3, url3_ref);
2714 // Transient entry should be gone.
2715 EXPECT_FALSE(controller.GetTransientEntry());
2716 EXPECT_EQ(url3_ref, controller.GetVisibleEntry()->GetURL());
2718 // Ensure the URLs are correct.
2719 EXPECT_EQ(controller.GetEntryCount(), 5);
2720 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
2721 EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), url1);
2722 EXPECT_EQ(controller.GetEntryAtIndex(2)->GetURL(), url2);
2723 EXPECT_EQ(controller.GetEntryAtIndex(3)->GetURL(), url3_ref);
2724 EXPECT_EQ(controller.GetEntryAtIndex(4)->GetURL(), url4);
2727 // Test that Reload initiates a new navigation to a transient entry's URL.
2728 TEST_F(NavigationControllerTest, ReloadTransient) {
2729 NavigationControllerImpl& controller = controller_impl();
2730 const GURL url0("http://foo/0");
2731 const GURL url1("http://foo/1");
2732 const GURL transient_url("http://foo/transient");
2734 // Load |url0|, and start a pending navigation to |url1|.
2735 controller.LoadURL(
2736 url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2737 main_test_rfh()->SendNavigate(0, url0);
2738 controller.LoadURL(
2739 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2741 // A transient entry is added, interrupting the navigation.
2742 NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
2743 transient_entry->SetURL(transient_url);
2744 controller.SetTransientEntry(transient_entry);
2745 EXPECT_TRUE(controller.GetTransientEntry());
2746 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
2748 // The page is reloaded, which should remove the pending entry for |url1| and
2749 // the transient entry for |transient_url|, and start a navigation to
2750 // |transient_url|.
2751 controller.Reload(true);
2752 EXPECT_FALSE(controller.GetTransientEntry());
2753 EXPECT_TRUE(controller.GetPendingEntry());
2754 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL());
2755 ASSERT_EQ(controller.GetEntryCount(), 1);
2756 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
2758 // Load of |transient_url| completes.
2759 main_test_rfh()->SendNavigate(1, transient_url);
2760 ASSERT_EQ(controller.GetEntryCount(), 2);
2761 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
2762 EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), transient_url);
2765 // Ensure that renderer initiated pending entries get replaced, so that we
2766 // don't show a stale virtual URL when a navigation commits.
2767 // See http://crbug.com/266922.
2768 TEST_F(NavigationControllerTest, RendererInitiatedPendingEntries) {
2769 NavigationControllerImpl& controller = controller_impl();
2770 Navigator* navigator =
2771 contents()->GetFrameTree()->root()->navigator();
2773 const GURL url1("nonexistent:12121");
2774 const GURL url1_fixed("http://nonexistent:12121/");
2775 const GURL url2("http://foo");
2777 // We create pending entries for renderer-initiated navigations so that we
2778 // can show them in new tabs when it is safe.
2779 navigator->DidStartProvisionalLoad(main_test_rfh(), -1, url1);
2781 // Simulate what happens if a BrowserURLHandler rewrites the URL, causing
2782 // the virtual URL to differ from the URL.
2783 controller.GetPendingEntry()->SetURL(url1_fixed);
2784 controller.GetPendingEntry()->SetVirtualURL(url1);
2786 EXPECT_EQ(url1_fixed, controller.GetPendingEntry()->GetURL());
2787 EXPECT_EQ(url1, controller.GetPendingEntry()->GetVirtualURL());
2788 EXPECT_TRUE(
2789 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
2790 is_renderer_initiated());
2792 // If the user clicks another link, we should replace the pending entry.
2793 navigator->DidStartProvisionalLoad(main_test_rfh(), -1, url2);
2794 EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL());
2795 EXPECT_EQ(url2, controller.GetPendingEntry()->GetVirtualURL());
2797 // Once it commits, the URL and virtual URL should reflect the actual page.
2798 main_test_rfh()->SendNavigate(0, url2);
2799 EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
2800 EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetVirtualURL());
2802 // We should not replace the pending entry for an error URL.
2803 navigator->DidStartProvisionalLoad(main_test_rfh(), -1, url1);
2804 EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
2805 navigator->DidStartProvisionalLoad(
2806 main_test_rfh(), -1, GURL(kUnreachableWebDataURL));
2807 EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
2809 // We should remember if the pending entry will replace the current one.
2810 // http://crbug.com/308444.
2811 navigator->DidStartProvisionalLoad(main_test_rfh(), -1, url1);
2812 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
2813 set_should_replace_entry(true);
2814 navigator->DidStartProvisionalLoad(main_test_rfh(), -1, url2);
2815 EXPECT_TRUE(
2816 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
2817 should_replace_entry());
2818 // TODO(nasko): Until OnNavigate is moved to RenderFrameHost, we need
2819 // to go through the RenderViewHost. The TestRenderViewHost routes navigations
2820 // to the main frame.
2821 main_test_rfh()->SendNavigate(0, url2);
2822 EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
2825 // Tests that the URLs for renderer-initiated navigations are not displayed to
2826 // the user until the navigation commits, to prevent URL spoof attacks.
2827 // See http://crbug.com/99016.
2828 TEST_F(NavigationControllerTest, DontShowRendererURLUntilCommit) {
2829 NavigationControllerImpl& controller = controller_impl();
2830 TestNotificationTracker notifications;
2831 RegisterForAllNavNotifications(&notifications, &controller);
2833 const GURL url0("http://foo/0");
2834 const GURL url1("http://foo/1");
2836 // For typed navigations (browser-initiated), both pending and visible entries
2837 // should update before commit.
2838 controller.LoadURL(url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2839 EXPECT_EQ(url0, controller.GetPendingEntry()->GetURL());
2840 EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
2841 main_test_rfh()->SendNavigate(0, url0);
2843 // For link clicks (renderer-initiated navigations), the pending entry should
2844 // update before commit but the visible should not.
2845 NavigationController::LoadURLParams load_url_params(url1);
2846 load_url_params.is_renderer_initiated = true;
2847 controller.LoadURLWithParams(load_url_params);
2848 EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
2849 EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
2850 EXPECT_TRUE(
2851 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
2852 is_renderer_initiated());
2854 // After commit, both visible should be updated, there should be no pending
2855 // entry, and we should no longer treat the entry as renderer-initiated.
2856 main_test_rfh()->SendNavigate(1, url1);
2857 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
2858 EXPECT_FALSE(controller.GetPendingEntry());
2859 EXPECT_FALSE(
2860 NavigationEntryImpl::FromNavigationEntry(
2861 controller.GetLastCommittedEntry())->is_renderer_initiated());
2863 notifications.Reset();
2866 // Tests that the URLs for renderer-initiated navigations in new tabs are
2867 // displayed to the user before commit, as long as the initial about:blank
2868 // page has not been modified. If so, we must revert to showing about:blank.
2869 // See http://crbug.com/9682.
2870 TEST_F(NavigationControllerTest, ShowRendererURLInNewTabUntilModified) {
2871 NavigationControllerImpl& controller = controller_impl();
2872 TestNotificationTracker notifications;
2873 RegisterForAllNavNotifications(&notifications, &controller);
2875 const GURL url("http://foo");
2877 // For renderer-initiated navigations in new tabs (with no committed entries),
2878 // we show the pending entry's URL as long as the about:blank page is not
2879 // modified.
2880 NavigationController::LoadURLParams load_url_params(url);
2881 load_url_params.transition_type = PAGE_TRANSITION_LINK;
2882 load_url_params.is_renderer_initiated = true;
2883 controller.LoadURLWithParams(load_url_params);
2884 EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
2885 EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
2886 EXPECT_TRUE(
2887 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
2888 is_renderer_initiated());
2889 EXPECT_TRUE(controller.IsInitialNavigation());
2890 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
2892 // There should be no title yet.
2893 EXPECT_TRUE(contents()->GetTitle().empty());
2895 // If something else modifies the contents of the about:blank page, then
2896 // we must revert to showing about:blank to avoid a URL spoof.
2897 main_test_rfh()->OnMessageReceived(FrameHostMsg_DidAccessInitialDocument(0));
2898 EXPECT_TRUE(contents()->HasAccessedInitialDocument());
2899 EXPECT_FALSE(controller.GetVisibleEntry());
2900 EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
2902 notifications.Reset();
2905 // Tests that the URLs for browser-initiated navigations in new tabs are
2906 // displayed to the user even after they fail, as long as the initial
2907 // about:blank page has not been modified. If so, we must revert to showing
2908 // about:blank. See http://crbug.com/355537.
2909 TEST_F(NavigationControllerTest, ShowBrowserURLAfterFailUntilModified) {
2910 NavigationControllerImpl& controller = controller_impl();
2911 TestNotificationTracker notifications;
2912 RegisterForAllNavNotifications(&notifications, &controller);
2914 const GURL url("http://foo");
2916 // For browser-initiated navigations in new tabs (with no committed entries),
2917 // we show the pending entry's URL as long as the about:blank page is not
2918 // modified. This is possible in cases that the user types a URL into a popup
2919 // tab created with a slow URL.
2920 NavigationController::LoadURLParams load_url_params(url);
2921 load_url_params.transition_type = PAGE_TRANSITION_TYPED;
2922 load_url_params.is_renderer_initiated = false;
2923 controller.LoadURLWithParams(load_url_params);
2924 EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
2925 EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
2926 EXPECT_FALSE(
2927 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
2928 is_renderer_initiated());
2929 EXPECT_TRUE(controller.IsInitialNavigation());
2930 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
2932 // There should be no title yet.
2933 EXPECT_TRUE(contents()->GetTitle().empty());
2935 // Suppose it aborts before committing, if it's a 204 or download or due to a
2936 // stop or a new navigation from the user. The URL should remain visible.
2937 FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
2938 params.error_code = net::ERR_ABORTED;
2939 params.error_description = base::string16();
2940 params.url = url;
2941 params.showing_repost_interstitial = false;
2942 main_test_rfh()->OnMessageReceived(
2943 FrameHostMsg_DidFailProvisionalLoadWithError(0, params));
2944 contents()->SetIsLoading(test_rvh(), false, true, NULL);
2945 EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
2947 // If something else later modifies the contents of the about:blank page, then
2948 // we must revert to showing about:blank to avoid a URL spoof.
2949 main_test_rfh()->OnMessageReceived(FrameHostMsg_DidAccessInitialDocument(0));
2950 EXPECT_TRUE(contents()->HasAccessedInitialDocument());
2951 EXPECT_FALSE(controller.GetVisibleEntry());
2952 EXPECT_FALSE(controller.GetPendingEntry());
2954 notifications.Reset();
2957 // Tests that the URLs for renderer-initiated navigations in new tabs are
2958 // displayed to the user even after they fail, as long as the initial
2959 // about:blank page has not been modified. If so, we must revert to showing
2960 // about:blank. See http://crbug.com/355537.
2961 TEST_F(NavigationControllerTest, ShowRendererURLAfterFailUntilModified) {
2962 NavigationControllerImpl& controller = controller_impl();
2963 TestNotificationTracker notifications;
2964 RegisterForAllNavNotifications(&notifications, &controller);
2966 const GURL url("http://foo");
2968 // For renderer-initiated navigations in new tabs (with no committed entries),
2969 // we show the pending entry's URL as long as the about:blank page is not
2970 // modified.
2971 NavigationController::LoadURLParams load_url_params(url);
2972 load_url_params.transition_type = PAGE_TRANSITION_LINK;
2973 load_url_params.is_renderer_initiated = true;
2974 controller.LoadURLWithParams(load_url_params);
2975 EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
2976 EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
2977 EXPECT_TRUE(
2978 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
2979 is_renderer_initiated());
2980 EXPECT_TRUE(controller.IsInitialNavigation());
2981 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
2983 // There should be no title yet.
2984 EXPECT_TRUE(contents()->GetTitle().empty());
2986 // Suppose it aborts before committing, if it's a 204 or download or due to a
2987 // stop or a new navigation from the user. The URL should remain visible.
2988 FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
2989 params.error_code = net::ERR_ABORTED;
2990 params.error_description = base::string16();
2991 params.url = url;
2992 params.showing_repost_interstitial = false;
2993 main_test_rfh()->OnMessageReceived(
2994 FrameHostMsg_DidFailProvisionalLoadWithError(0, params));
2995 EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
2997 // If something else later modifies the contents of the about:blank page, then
2998 // we must revert to showing about:blank to avoid a URL spoof.
2999 main_test_rfh()->OnMessageReceived(FrameHostMsg_DidAccessInitialDocument(0));
3000 EXPECT_TRUE(contents()->HasAccessedInitialDocument());
3001 EXPECT_FALSE(controller.GetVisibleEntry());
3002 EXPECT_EQ(url, controller.GetPendingEntry()->GetURL());
3004 notifications.Reset();
3007 TEST_F(NavigationControllerTest, DontShowRendererURLInNewTabAfterCommit) {
3008 NavigationControllerImpl& controller = controller_impl();
3009 TestNotificationTracker notifications;
3010 RegisterForAllNavNotifications(&notifications, &controller);
3012 const GURL url1("http://foo/eh");
3013 const GURL url2("http://foo/bee");
3015 // For renderer-initiated navigations in new tabs (with no committed entries),
3016 // we show the pending entry's URL as long as the about:blank page is not
3017 // modified.
3018 NavigationController::LoadURLParams load_url_params(url1);
3019 load_url_params.transition_type = PAGE_TRANSITION_LINK;
3020 load_url_params.is_renderer_initiated = true;
3021 controller.LoadURLWithParams(load_url_params);
3022 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
3023 EXPECT_TRUE(
3024 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
3025 is_renderer_initiated());
3026 EXPECT_TRUE(controller.IsInitialNavigation());
3027 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
3029 // Simulate a commit and then starting a new pending navigation.
3030 main_test_rfh()->SendNavigate(0, url1);
3031 NavigationController::LoadURLParams load_url2_params(url2);
3032 load_url2_params.transition_type = PAGE_TRANSITION_LINK;
3033 load_url2_params.is_renderer_initiated = true;
3034 controller.LoadURLWithParams(load_url2_params);
3036 // We should not consider this an initial navigation, and thus should
3037 // not show the pending URL.
3038 EXPECT_FALSE(contents()->HasAccessedInitialDocument());
3039 EXPECT_FALSE(controller.IsInitialNavigation());
3040 EXPECT_TRUE(controller.GetVisibleEntry());
3041 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
3043 notifications.Reset();
3046 // Tests that IsInPageNavigation returns appropriate results. Prevents
3047 // regression for bug 1126349.
3048 TEST_F(NavigationControllerTest, IsInPageNavigation) {
3049 NavigationControllerImpl& controller = controller_impl();
3050 // Navigate to URL with no refs.
3051 const GURL url("http://www.google.com/home.html");
3052 main_test_rfh()->SendNavigate(0, url);
3054 // Reloading the page is not an in-page navigation.
3055 EXPECT_FALSE(controller.IsURLInPageNavigation(url));
3056 const GURL other_url("http://www.google.com/add.html");
3057 EXPECT_FALSE(controller.IsURLInPageNavigation(other_url));
3058 const GURL url_with_ref("http://www.google.com/home.html#my_ref");
3059 EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref));
3061 // Navigate to URL with refs.
3062 main_test_rfh()->SendNavigate(1, url_with_ref);
3064 // Reloading the page is not an in-page navigation.
3065 EXPECT_FALSE(controller.IsURLInPageNavigation(url_with_ref));
3066 EXPECT_FALSE(controller.IsURLInPageNavigation(url));
3067 EXPECT_FALSE(controller.IsURLInPageNavigation(other_url));
3068 const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref");
3069 EXPECT_TRUE(controller.IsURLInPageNavigation(other_url_with_ref));
3071 // Going to the same url again will be considered in-page
3072 // if the renderer says it is even if the navigation type isn't IN_PAGE.
3073 EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref, true,
3074 NAVIGATION_TYPE_UNKNOWN));
3076 // Going back to the non ref url will be considered in-page if the navigation
3077 // type is IN_PAGE.
3078 EXPECT_TRUE(controller.IsURLInPageNavigation(url, true,
3079 NAVIGATION_TYPE_IN_PAGE));
3082 // Some pages can have subframes with the same base URL (minus the reference) as
3083 // the main page. Even though this is hard, it can happen, and we don't want
3084 // these subframe navigations to affect the toplevel document. They should
3085 // instead be ignored. http://crbug.com/5585
3086 TEST_F(NavigationControllerTest, SameSubframe) {
3087 NavigationControllerImpl& controller = controller_impl();
3088 // Navigate the main frame.
3089 const GURL url("http://www.google.com/");
3090 main_test_rfh()->SendNavigate(0, url);
3092 // We should be at the first navigation entry.
3093 EXPECT_EQ(controller.GetEntryCount(), 1);
3094 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
3096 // Navigate a subframe that would normally count as in-page.
3097 const GURL subframe("http://www.google.com/#");
3098 FrameHostMsg_DidCommitProvisionalLoad_Params params;
3099 params.page_id = 0;
3100 params.url = subframe;
3101 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
3102 params.should_update_history = false;
3103 params.gesture = NavigationGestureAuto;
3104 params.is_post = false;
3105 params.page_state = PageState::CreateFromURL(subframe);
3106 LoadCommittedDetails details;
3107 EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params,
3108 &details));
3110 // Nothing should have changed.
3111 EXPECT_EQ(controller.GetEntryCount(), 1);
3112 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
3115 // Make sure that on cloning a WebContentsImpl and going back needs_reload is
3116 // false.
3117 TEST_F(NavigationControllerTest, CloneAndGoBack) {
3118 NavigationControllerImpl& controller = controller_impl();
3119 const GURL url1("http://foo1");
3120 const GURL url2("http://foo2");
3121 const base::string16 title(base::ASCIIToUTF16("Title"));
3123 NavigateAndCommit(url1);
3124 controller.GetVisibleEntry()->SetTitle(title);
3125 NavigateAndCommit(url2);
3127 scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
3129 ASSERT_EQ(2, clone->GetController().GetEntryCount());
3130 EXPECT_TRUE(clone->GetController().NeedsReload());
3131 clone->GetController().GoBack();
3132 // Navigating back should have triggered needs_reload_ to go false.
3133 EXPECT_FALSE(clone->GetController().NeedsReload());
3135 // Ensure that the pending URL and its title are visible.
3136 EXPECT_EQ(url1, clone->GetController().GetVisibleEntry()->GetURL());
3137 EXPECT_EQ(title, clone->GetTitle());
3140 // Make sure that reloading a cloned tab doesn't change its pending entry index.
3141 // See http://crbug.com/234491.
3142 TEST_F(NavigationControllerTest, CloneAndReload) {
3143 NavigationControllerImpl& controller = controller_impl();
3144 const GURL url1("http://foo1");
3145 const GURL url2("http://foo2");
3146 const base::string16 title(base::ASCIIToUTF16("Title"));
3148 NavigateAndCommit(url1);
3149 controller.GetVisibleEntry()->SetTitle(title);
3150 NavigateAndCommit(url2);
3152 scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
3153 clone->GetController().LoadIfNecessary();
3155 ASSERT_EQ(2, clone->GetController().GetEntryCount());
3156 EXPECT_EQ(1, clone->GetController().GetPendingEntryIndex());
3158 clone->GetController().Reload(true);
3159 EXPECT_EQ(1, clone->GetController().GetPendingEntryIndex());
3162 // Make sure that cloning a WebContentsImpl doesn't copy interstitials.
3163 TEST_F(NavigationControllerTest, CloneOmitsInterstitials) {
3164 NavigationControllerImpl& controller = controller_impl();
3165 const GURL url1("http://foo1");
3166 const GURL url2("http://foo2");
3168 NavigateAndCommit(url1);
3169 NavigateAndCommit(url2);
3171 // Add an interstitial entry. Should be deleted with controller.
3172 NavigationEntryImpl* interstitial_entry = new NavigationEntryImpl();
3173 interstitial_entry->set_page_type(PAGE_TYPE_INTERSTITIAL);
3174 controller.SetTransientEntry(interstitial_entry);
3176 scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
3178 ASSERT_EQ(2, clone->GetController().GetEntryCount());
3181 // Test requesting and triggering a lazy reload.
3182 TEST_F(NavigationControllerTest, LazyReload) {
3183 NavigationControllerImpl& controller = controller_impl();
3184 const GURL url("http://foo");
3185 NavigateAndCommit(url);
3186 ASSERT_FALSE(controller.NeedsReload());
3188 // Request a reload to happen when the controller becomes active (e.g. after
3189 // the renderer gets killed in background on Android).
3190 controller.SetNeedsReload();
3191 ASSERT_TRUE(controller.NeedsReload());
3193 // Set the controller as active, triggering the requested reload.
3194 controller.SetActive(true);
3195 ASSERT_FALSE(controller.NeedsReload());
3198 // Tests a subframe navigation while a toplevel navigation is pending.
3199 // http://crbug.com/43967
3200 TEST_F(NavigationControllerTest, SubframeWhilePending) {
3201 NavigationControllerImpl& controller = controller_impl();
3202 // Load the first page.
3203 const GURL url1("http://foo/");
3204 NavigateAndCommit(url1);
3206 // Now start a pending load to a totally different page, but don't commit it.
3207 const GURL url2("http://bar/");
3208 controller.LoadURL(
3209 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
3211 // Send a subframe update from the first page, as if one had just
3212 // automatically loaded. Auto subframes don't increment the page ID.
3213 const GURL url1_sub("http://foo/subframe");
3214 FrameHostMsg_DidCommitProvisionalLoad_Params params;
3215 params.page_id = controller.GetLastCommittedEntry()->GetPageID();
3216 params.url = url1_sub;
3217 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
3218 params.should_update_history = false;
3219 params.gesture = NavigationGestureAuto;
3220 params.is_post = false;
3221 params.page_state = PageState::CreateFromURL(url1_sub);
3222 LoadCommittedDetails details;
3224 // This should return false meaning that nothing was actually updated.
3225 EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params,
3226 &details));
3228 // The notification should have updated the last committed one, and not
3229 // the pending load.
3230 EXPECT_EQ(url1, controller.GetLastCommittedEntry()->GetURL());
3232 // The active entry should be unchanged by the subframe load.
3233 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
3236 // Test CopyStateFrom with 2 urls, the first selected and nothing in the target.
3237 TEST_F(NavigationControllerTest, CopyStateFrom) {
3238 NavigationControllerImpl& controller = controller_impl();
3239 const GURL url1("http://foo1");
3240 const GURL url2("http://foo2");
3242 NavigateAndCommit(url1);
3243 NavigateAndCommit(url2);
3244 controller.GoBack();
3245 contents()->CommitPendingNavigation();
3247 scoped_ptr<TestWebContents> other_contents(
3248 static_cast<TestWebContents*>(CreateTestWebContents()));
3249 NavigationControllerImpl& other_controller = other_contents->GetController();
3250 other_controller.CopyStateFrom(controller);
3252 // other_controller should now contain 2 urls.
3253 ASSERT_EQ(2, other_controller.GetEntryCount());
3254 // We should be looking at the first one.
3255 ASSERT_EQ(0, other_controller.GetCurrentEntryIndex());
3257 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3258 EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
3259 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
3260 // This is a different site than url1, so the IDs start again at 0.
3261 EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID());
3263 // The max page ID map should be copied over and updated with the max page ID
3264 // from the current tab.
3265 SiteInstance* instance1 =
3266 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
3267 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3269 // Ensure the SessionStorageNamespaceMaps are the same size and have
3270 // the same partitons loaded.
3272 // TODO(ajwong): We should load a url from a different partition earlier
3273 // to make sure this map has more than one entry.
3274 const SessionStorageNamespaceMap& session_storage_namespace_map =
3275 controller.GetSessionStorageNamespaceMap();
3276 const SessionStorageNamespaceMap& other_session_storage_namespace_map =
3277 other_controller.GetSessionStorageNamespaceMap();
3278 EXPECT_EQ(session_storage_namespace_map.size(),
3279 other_session_storage_namespace_map.size());
3280 for (SessionStorageNamespaceMap::const_iterator it =
3281 session_storage_namespace_map.begin();
3282 it != session_storage_namespace_map.end();
3283 ++it) {
3284 SessionStorageNamespaceMap::const_iterator other =
3285 other_session_storage_namespace_map.find(it->first);
3286 EXPECT_TRUE(other != other_session_storage_namespace_map.end());
3290 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
3291 TEST_F(NavigationControllerTest, CopyStateFromAndPrune) {
3292 NavigationControllerImpl& controller = controller_impl();
3293 const GURL url1("http://foo/1");
3294 const GURL url2("http://foo/2");
3295 const GURL url3("http://foo/3");
3297 NavigateAndCommit(url1);
3298 NavigateAndCommit(url2);
3300 // First two entries should have the same SiteInstance.
3301 SiteInstance* instance1 =
3302 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0));
3303 SiteInstance* instance2 =
3304 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1));
3305 EXPECT_EQ(instance1, instance2);
3306 EXPECT_EQ(0, controller.GetEntryAtIndex(0)->GetPageID());
3307 EXPECT_EQ(1, controller.GetEntryAtIndex(1)->GetPageID());
3308 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1));
3310 scoped_ptr<TestWebContents> other_contents(
3311 static_cast<TestWebContents*>(CreateTestWebContents()));
3312 NavigationControllerImpl& other_controller = other_contents->GetController();
3313 other_contents->NavigateAndCommit(url3);
3314 other_contents->ExpectSetHistoryLengthAndPrune(
3315 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
3316 other_controller.GetEntryAtIndex(0)->GetPageID());
3317 other_controller.CopyStateFromAndPrune(&controller, false);
3319 // other_controller should now contain the 3 urls: url1, url2 and url3.
3321 ASSERT_EQ(3, other_controller.GetEntryCount());
3323 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
3325 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3326 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
3327 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
3328 EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
3329 EXPECT_EQ(1, other_controller.GetEntryAtIndex(1)->GetPageID());
3330 EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
3332 // A new SiteInstance in a different BrowsingInstance should be used for the
3333 // new tab.
3334 SiteInstance* instance3 =
3335 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
3336 EXPECT_NE(instance3, instance1);
3337 EXPECT_FALSE(instance3->IsRelatedSiteInstance(instance1));
3339 // The max page ID map should be copied over and updated with the max page ID
3340 // from the current tab.
3341 EXPECT_EQ(1, other_contents->GetMaxPageIDForSiteInstance(instance1));
3342 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance3));
3345 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry in
3346 // the target.
3347 TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) {
3348 NavigationControllerImpl& controller = controller_impl();
3349 const GURL url1("http://foo1");
3350 const GURL url2("http://foo2");
3351 const GURL url3("http://foo3");
3353 NavigateAndCommit(url1);
3354 NavigateAndCommit(url2);
3355 controller.GoBack();
3356 contents()->CommitPendingNavigation();
3358 scoped_ptr<TestWebContents> other_contents(
3359 static_cast<TestWebContents*>(CreateTestWebContents()));
3360 NavigationControllerImpl& other_controller = other_contents->GetController();
3361 other_contents->NavigateAndCommit(url3);
3362 other_contents->ExpectSetHistoryLengthAndPrune(
3363 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
3364 other_controller.GetEntryAtIndex(0)->GetPageID());
3365 other_controller.CopyStateFromAndPrune(&controller, false);
3367 // other_controller should now contain: url1, url3
3369 ASSERT_EQ(2, other_controller.GetEntryCount());
3370 ASSERT_EQ(1, other_controller.GetCurrentEntryIndex());
3372 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3373 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
3374 EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID());
3376 // The max page ID map should be copied over and updated with the max page ID
3377 // from the current tab.
3378 SiteInstance* instance1 =
3379 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
3380 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3383 // Test CopyStateFromAndPrune with 2 urls, the last selected and 2 entries in
3384 // the target.
3385 TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) {
3386 NavigationControllerImpl& controller = controller_impl();
3387 const GURL url1("http://foo1");
3388 const GURL url2("http://foo2");
3389 const GURL url3("http://foo3");
3390 const GURL url4("http://foo4");
3392 NavigateAndCommit(url1);
3393 NavigateAndCommit(url2);
3395 scoped_ptr<TestWebContents> other_contents(
3396 static_cast<TestWebContents*>(CreateTestWebContents()));
3397 NavigationControllerImpl& other_controller = other_contents->GetController();
3398 other_contents->NavigateAndCommit(url3);
3399 other_contents->NavigateAndCommit(url4);
3400 other_contents->ExpectSetHistoryLengthAndPrune(
3401 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1)), 2,
3402 other_controller.GetEntryAtIndex(0)->GetPageID());
3403 other_controller.CopyStateFromAndPrune(&controller, false);
3405 // other_controller should now contain: url1, url2, url4
3407 ASSERT_EQ(3, other_controller.GetEntryCount());
3408 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
3410 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3411 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
3412 EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
3414 // The max page ID map should be copied over and updated with the max page ID
3415 // from the current tab.
3416 SiteInstance* instance1 =
3417 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
3418 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3421 // Test CopyStateFromAndPrune with 2 urls, 2 entries in the target, with
3422 // not the last entry selected in the target.
3423 TEST_F(NavigationControllerTest, CopyStateFromAndPruneNotLast) {
3424 NavigationControllerImpl& controller = controller_impl();
3425 const GURL url1("http://foo1");
3426 const GURL url2("http://foo2");
3427 const GURL url3("http://foo3");
3428 const GURL url4("http://foo4");
3430 NavigateAndCommit(url1);
3431 NavigateAndCommit(url2);
3433 scoped_ptr<TestWebContents> other_contents(
3434 static_cast<TestWebContents*>(CreateTestWebContents()));
3435 NavigationControllerImpl& other_controller = other_contents->GetController();
3436 other_contents->NavigateAndCommit(url3);
3437 other_contents->NavigateAndCommit(url4);
3438 other_controller.GoBack();
3439 other_contents->CommitPendingNavigation();
3440 other_contents->ExpectSetHistoryLengthAndPrune(
3441 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
3442 other_controller.GetEntryAtIndex(0)->GetPageID());
3443 other_controller.CopyStateFromAndPrune(&controller, false);
3445 // other_controller should now contain: url1, url2, url3
3447 ASSERT_EQ(3, other_controller.GetEntryCount());
3448 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
3450 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3451 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
3452 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
3454 // The max page ID map should be copied over and updated with the max page ID
3455 // from the current tab.
3456 SiteInstance* instance1 =
3457 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
3458 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3461 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry plus
3462 // a pending entry in the target.
3463 TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending) {
3464 NavigationControllerImpl& controller = controller_impl();
3465 const GURL url1("http://foo1");
3466 const GURL url2("http://foo2");
3467 const GURL url3("http://foo3");
3468 const GURL url4("http://foo4");
3470 NavigateAndCommit(url1);
3471 NavigateAndCommit(url2);
3472 controller.GoBack();
3473 contents()->CommitPendingNavigation();
3475 scoped_ptr<TestWebContents> other_contents(
3476 static_cast<TestWebContents*>(CreateTestWebContents()));
3477 NavigationControllerImpl& other_controller = other_contents->GetController();
3478 other_contents->NavigateAndCommit(url3);
3479 other_controller.LoadURL(
3480 url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
3481 other_contents->ExpectSetHistoryLengthAndPrune(
3482 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
3483 other_controller.GetEntryAtIndex(0)->GetPageID());
3484 other_controller.CopyStateFromAndPrune(&controller, false);
3486 // other_controller should now contain url1, url3, and a pending entry
3487 // for url4.
3489 ASSERT_EQ(2, other_controller.GetEntryCount());
3490 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
3492 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3493 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
3495 // And there should be a pending entry for url4.
3496 ASSERT_TRUE(other_controller.GetPendingEntry());
3497 EXPECT_EQ(url4, other_controller.GetPendingEntry()->GetURL());
3499 // The max page ID map should be copied over and updated with the max page ID
3500 // from the current tab.
3501 SiteInstance* instance1 =
3502 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
3503 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3506 // Test CopyStateFromAndPrune with 1 url in the source, 1 entry and a pending
3507 // client redirect entry (with the same page ID) in the target. This used to
3508 // crash because the last committed entry would be pruned but max_page_id
3509 // remembered the page ID (http://crbug.com/234809).
3510 TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending2) {
3511 NavigationControllerImpl& controller = controller_impl();
3512 const GURL url1("http://foo1");
3513 const GURL url2a("http://foo2/a");
3514 const GURL url2b("http://foo2/b");
3516 NavigateAndCommit(url1);
3518 scoped_ptr<TestWebContents> other_contents(
3519 static_cast<TestWebContents*>(CreateTestWebContents()));
3520 NavigationControllerImpl& other_controller = other_contents->GetController();
3521 other_contents->NavigateAndCommit(url2a);
3522 // Simulate a client redirect, which has the same page ID as entry 2a.
3523 other_controller.LoadURL(
3524 url2b, Referrer(), PAGE_TRANSITION_LINK, std::string());
3525 other_controller.GetPendingEntry()->SetPageID(
3526 other_controller.GetLastCommittedEntry()->GetPageID());
3528 other_contents->ExpectSetHistoryLengthAndPrune(
3529 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
3530 other_controller.GetEntryAtIndex(0)->GetPageID());
3531 other_controller.CopyStateFromAndPrune(&controller, false);
3533 // other_controller should now contain url1, url2a, and a pending entry
3534 // for url2b.
3536 ASSERT_EQ(2, other_controller.GetEntryCount());
3537 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
3539 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3540 EXPECT_EQ(url2a, other_controller.GetEntryAtIndex(1)->GetURL());
3542 // And there should be a pending entry for url4.
3543 ASSERT_TRUE(other_controller.GetPendingEntry());
3544 EXPECT_EQ(url2b, other_controller.GetPendingEntry()->GetURL());
3546 // Let the pending entry commit.
3547 other_contents->CommitPendingNavigation();
3549 // The max page ID map should be copied over and updated with the max page ID
3550 // from the current tab.
3551 SiteInstance* instance1 =
3552 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
3553 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3556 // Test CopyStateFromAndPrune with 2 urls, a back navigation pending in the
3557 // source, and 1 entry in the target. The back pending entry should be ignored.
3558 TEST_F(NavigationControllerTest, CopyStateFromAndPruneSourcePending) {
3559 NavigationControllerImpl& controller = controller_impl();
3560 const GURL url1("http://foo1");
3561 const GURL url2("http://foo2");
3562 const GURL url3("http://foo3");
3564 NavigateAndCommit(url1);
3565 NavigateAndCommit(url2);
3566 controller.GoBack();
3568 scoped_ptr<TestWebContents> other_contents(
3569 static_cast<TestWebContents*>(CreateTestWebContents()));
3570 NavigationControllerImpl& other_controller = other_contents->GetController();
3571 other_contents->NavigateAndCommit(url3);
3572 other_contents->ExpectSetHistoryLengthAndPrune(
3573 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
3574 other_controller.GetEntryAtIndex(0)->GetPageID());
3575 other_controller.CopyStateFromAndPrune(&controller, false);
3577 // other_controller should now contain: url1, url2, url3
3579 ASSERT_EQ(3, other_controller.GetEntryCount());
3580 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
3582 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3583 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
3584 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
3585 EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
3587 // The max page ID map should be copied over and updated with the max page ID
3588 // from the current tab.
3589 SiteInstance* instance1 =
3590 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
3591 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3594 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest,
3595 // when the max entry count is 3. We should prune one entry.
3596 TEST_F(NavigationControllerTest, CopyStateFromAndPruneMaxEntries) {
3597 NavigationControllerImpl& controller = controller_impl();
3598 size_t original_count = NavigationControllerImpl::max_entry_count();
3599 const int kMaxEntryCount = 3;
3601 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
3603 const GURL url1("http://foo/1");
3604 const GURL url2("http://foo/2");
3605 const GURL url3("http://foo/3");
3606 const GURL url4("http://foo/4");
3608 // Create a PrunedListener to observe prune notifications.
3609 PrunedListener listener(&controller);
3611 NavigateAndCommit(url1);
3612 NavigateAndCommit(url2);
3613 NavigateAndCommit(url3);
3615 scoped_ptr<TestWebContents> other_contents(
3616 static_cast<TestWebContents*>(CreateTestWebContents()));
3617 NavigationControllerImpl& other_controller = other_contents->GetController();
3618 other_contents->NavigateAndCommit(url4);
3619 other_contents->ExpectSetHistoryLengthAndPrune(
3620 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
3621 other_controller.GetEntryAtIndex(0)->GetPageID());
3622 other_controller.CopyStateFromAndPrune(&controller, false);
3624 // We should have received a pruned notification.
3625 EXPECT_EQ(1, listener.notification_count_);
3626 EXPECT_TRUE(listener.details_.from_front);
3627 EXPECT_EQ(1, listener.details_.count);
3629 // other_controller should now contain only 3 urls: url2, url3 and url4.
3631 ASSERT_EQ(3, other_controller.GetEntryCount());
3633 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
3635 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(0)->GetURL());
3636 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
3637 EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
3638 EXPECT_EQ(1, other_controller.GetEntryAtIndex(0)->GetPageID());
3639 EXPECT_EQ(2, other_controller.GetEntryAtIndex(1)->GetPageID());
3640 EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
3642 NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
3645 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest, with
3646 // replace_entry set to true.
3647 TEST_F(NavigationControllerTest, CopyStateFromAndPruneReplaceEntry) {
3648 NavigationControllerImpl& controller = controller_impl();
3649 const GURL url1("http://foo/1");
3650 const GURL url2("http://foo/2");
3651 const GURL url3("http://foo/3");
3653 NavigateAndCommit(url1);
3654 NavigateAndCommit(url2);
3656 // First two entries should have the same SiteInstance.
3657 SiteInstance* instance1 =
3658 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0));
3659 SiteInstance* instance2 =
3660 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1));
3661 EXPECT_EQ(instance1, instance2);
3662 EXPECT_EQ(0, controller.GetEntryAtIndex(0)->GetPageID());
3663 EXPECT_EQ(1, controller.GetEntryAtIndex(1)->GetPageID());
3664 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1));
3666 scoped_ptr<TestWebContents> other_contents(
3667 static_cast<TestWebContents*>(CreateTestWebContents()));
3668 NavigationControllerImpl& other_controller = other_contents->GetController();
3669 other_contents->NavigateAndCommit(url3);
3670 other_contents->ExpectSetHistoryLengthAndPrune(
3671 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
3672 other_controller.GetEntryAtIndex(0)->GetPageID());
3673 other_controller.CopyStateFromAndPrune(&controller, true);
3675 // other_controller should now contain the 2 urls: url1 and url3.
3677 ASSERT_EQ(2, other_controller.GetEntryCount());
3679 ASSERT_EQ(1, other_controller.GetCurrentEntryIndex());
3681 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3682 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
3683 EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
3684 EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID());
3686 // A new SiteInstance in a different BrowsingInstance should be used for the
3687 // new tab.
3688 SiteInstance* instance3 =
3689 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
3690 EXPECT_NE(instance3, instance1);
3691 EXPECT_FALSE(instance3->IsRelatedSiteInstance(instance1));
3693 // The max page ID map should be copied over and updated with the max page ID
3694 // from the current tab.
3695 EXPECT_EQ(1, other_contents->GetMaxPageIDForSiteInstance(instance1));
3696 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance3));
3699 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest, when the max
3700 // entry count is 3 and replace_entry is true. We should not prune entries.
3701 TEST_F(NavigationControllerTest, CopyStateFromAndPruneMaxEntriesReplaceEntry) {
3702 NavigationControllerImpl& controller = controller_impl();
3703 size_t original_count = NavigationControllerImpl::max_entry_count();
3704 const int kMaxEntryCount = 3;
3706 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
3708 const GURL url1("http://foo/1");
3709 const GURL url2("http://foo/2");
3710 const GURL url3("http://foo/3");
3711 const GURL url4("http://foo/4");
3713 // Create a PrunedListener to observe prune notifications.
3714 PrunedListener listener(&controller);
3716 NavigateAndCommit(url1);
3717 NavigateAndCommit(url2);
3718 NavigateAndCommit(url3);
3720 scoped_ptr<TestWebContents> other_contents(
3721 static_cast<TestWebContents*>(CreateTestWebContents()));
3722 NavigationControllerImpl& other_controller = other_contents->GetController();
3723 other_contents->NavigateAndCommit(url4);
3724 other_contents->ExpectSetHistoryLengthAndPrune(
3725 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
3726 other_controller.GetEntryAtIndex(0)->GetPageID());
3727 other_controller.CopyStateFromAndPrune(&controller, true);
3729 // We should have received no pruned notification.
3730 EXPECT_EQ(0, listener.notification_count_);
3732 // other_controller should now contain only 3 urls: url1, url2 and url4.
3734 ASSERT_EQ(3, other_controller.GetEntryCount());
3736 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
3738 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3739 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
3740 EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
3741 EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
3742 EXPECT_EQ(1, other_controller.GetEntryAtIndex(1)->GetPageID());
3743 EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
3745 NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
3748 // Tests that we can navigate to the restored entries
3749 // imported by CopyStateFromAndPrune.
3750 TEST_F(NavigationControllerTest, CopyRestoredStateAndNavigate) {
3751 const GURL kRestoredUrls[] = {
3752 GURL("http://site1.com"),
3753 GURL("http://site2.com"),
3755 const GURL kInitialUrl("http://site3.com");
3757 std::vector<NavigationEntry*> entries;
3758 for (size_t i = 0; i < arraysize(kRestoredUrls); ++i) {
3759 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
3760 kRestoredUrls[i], Referrer(), PAGE_TRANSITION_RELOAD, false,
3761 std::string(), browser_context());
3762 entry->SetPageID(static_cast<int>(i));
3763 entries.push_back(entry);
3766 // Create a WebContents with restored entries.
3767 scoped_ptr<TestWebContents> source_contents(
3768 static_cast<TestWebContents*>(CreateTestWebContents()));
3769 NavigationControllerImpl& source_controller =
3770 source_contents->GetController();
3771 source_controller.Restore(
3772 entries.size() - 1,
3773 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
3774 &entries);
3775 ASSERT_EQ(0u, entries.size());
3776 source_controller.LoadIfNecessary();
3777 source_contents->CommitPendingNavigation();
3779 // Load a page, then copy state from |source_contents|.
3780 NavigateAndCommit(kInitialUrl);
3781 contents()->ExpectSetHistoryLengthAndPrune(
3782 GetSiteInstanceFromEntry(controller_impl().GetEntryAtIndex(0)), 2,
3783 controller_impl().GetEntryAtIndex(0)->GetPageID());
3784 controller_impl().CopyStateFromAndPrune(&source_controller, false);
3785 ASSERT_EQ(3, controller_impl().GetEntryCount());
3787 // Go back to the first entry one at a time and
3788 // verify that it works as expected.
3789 EXPECT_EQ(2, controller_impl().GetCurrentEntryIndex());
3790 EXPECT_EQ(kInitialUrl, controller_impl().GetActiveEntry()->GetURL());
3792 controller_impl().GoBack();
3793 contents()->CommitPendingNavigation();
3794 EXPECT_EQ(1, controller_impl().GetCurrentEntryIndex());
3795 EXPECT_EQ(kRestoredUrls[1], controller_impl().GetActiveEntry()->GetURL());
3797 controller_impl().GoBack();
3798 contents()->CommitPendingNavigation();
3799 EXPECT_EQ(0, controller_impl().GetCurrentEntryIndex());
3800 EXPECT_EQ(kRestoredUrls[0], controller_impl().GetActiveEntry()->GetURL());
3803 // Tests that navigations initiated from the page (with the history object)
3804 // work as expected, creating pending entries.
3805 TEST_F(NavigationControllerTest, HistoryNavigate) {
3806 NavigationControllerImpl& controller = controller_impl();
3807 const GURL url1("http://foo/1");
3808 const GURL url2("http://foo/2");
3809 const GURL url3("http://foo/3");
3811 NavigateAndCommit(url1);
3812 NavigateAndCommit(url2);
3813 NavigateAndCommit(url3);
3814 controller.GoBack();
3815 contents()->CommitPendingNavigation();
3817 // Simulate the page calling history.back(). It should create a pending entry.
3818 contents()->OnGoToEntryAtOffset(-1);
3819 EXPECT_EQ(0, controller.GetPendingEntryIndex());
3820 // The actual cross-navigation is suspended until the current RVH tells us
3821 // it unloaded, simulate that.
3822 contents()->ProceedWithCrossSiteNavigation();
3823 // Also make sure we told the page to navigate.
3824 const IPC::Message* message =
3825 process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID);
3826 ASSERT_TRUE(message != NULL);
3827 Tuple1<FrameMsg_Navigate_Params> nav_params;
3828 FrameMsg_Navigate::Read(message, &nav_params);
3829 EXPECT_EQ(url1, nav_params.a.url);
3830 process()->sink().ClearMessages();
3832 // Now test history.forward()
3833 contents()->OnGoToEntryAtOffset(2);
3834 EXPECT_EQ(2, controller.GetPendingEntryIndex());
3835 // The actual cross-navigation is suspended until the current RVH tells us
3836 // it unloaded, simulate that.
3837 contents()->ProceedWithCrossSiteNavigation();
3838 message = process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID);
3839 ASSERT_TRUE(message != NULL);
3840 FrameMsg_Navigate::Read(message, &nav_params);
3841 EXPECT_EQ(url3, nav_params.a.url);
3842 process()->sink().ClearMessages();
3844 controller.DiscardNonCommittedEntries();
3846 // Make sure an extravagant history.go() doesn't break.
3847 contents()->OnGoToEntryAtOffset(120); // Out of bounds.
3848 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3849 message = process()->sink().GetFirstMessageMatching(FrameMsg_Navigate::ID);
3850 EXPECT_TRUE(message == NULL);
3853 // Test call to PruneAllButLastCommitted for the only entry.
3854 TEST_F(NavigationControllerTest, PruneAllButLastCommittedForSingle) {
3855 NavigationControllerImpl& controller = controller_impl();
3856 const GURL url1("http://foo1");
3857 NavigateAndCommit(url1);
3859 contents()->ExpectSetHistoryLengthAndPrune(
3860 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0,
3861 controller.GetEntryAtIndex(0)->GetPageID());
3863 controller.PruneAllButLastCommitted();
3865 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3866 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1);
3869 // Test call to PruneAllButLastCommitted for first entry.
3870 TEST_F(NavigationControllerTest, PruneAllButLastCommittedForFirst) {
3871 NavigationControllerImpl& controller = controller_impl();
3872 const GURL url1("http://foo/1");
3873 const GURL url2("http://foo/2");
3874 const GURL url3("http://foo/3");
3876 NavigateAndCommit(url1);
3877 NavigateAndCommit(url2);
3878 NavigateAndCommit(url3);
3879 controller.GoBack();
3880 controller.GoBack();
3881 contents()->CommitPendingNavigation();
3883 contents()->ExpectSetHistoryLengthAndPrune(
3884 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0,
3885 controller.GetEntryAtIndex(0)->GetPageID());
3887 controller.PruneAllButLastCommitted();
3889 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3890 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1);
3893 // Test call to PruneAllButLastCommitted for intermediate entry.
3894 TEST_F(NavigationControllerTest, PruneAllButLastCommittedForIntermediate) {
3895 NavigationControllerImpl& controller = controller_impl();
3896 const GURL url1("http://foo/1");
3897 const GURL url2("http://foo/2");
3898 const GURL url3("http://foo/3");
3900 NavigateAndCommit(url1);
3901 NavigateAndCommit(url2);
3902 NavigateAndCommit(url3);
3903 controller.GoBack();
3904 contents()->CommitPendingNavigation();
3906 contents()->ExpectSetHistoryLengthAndPrune(
3907 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1)), 0,
3908 controller.GetEntryAtIndex(1)->GetPageID());
3910 controller.PruneAllButLastCommitted();
3912 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3913 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url2);
3916 // Test call to PruneAllButLastCommitted for a pending entry that is not yet in
3917 // the list of entries.
3918 TEST_F(NavigationControllerTest, PruneAllButLastCommittedForPendingNotInList) {
3919 NavigationControllerImpl& controller = controller_impl();
3920 const GURL url1("http://foo/1");
3921 const GURL url2("http://foo/2");
3922 const GURL url3("http://foo/3");
3924 NavigateAndCommit(url1);
3925 NavigateAndCommit(url2);
3927 // Create a pending entry that is not in the entry list.
3928 controller.LoadURL(
3929 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
3930 EXPECT_TRUE(controller.GetPendingEntry());
3931 EXPECT_EQ(2, controller.GetEntryCount());
3933 contents()->ExpectSetHistoryLengthAndPrune(
3934 NULL, 0, controller.GetPendingEntry()->GetPageID());
3935 controller.PruneAllButLastCommitted();
3937 // We should only have the last committed and pending entries at this point,
3938 // and the pending entry should still not be in the entry list.
3939 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
3940 EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL());
3941 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3942 EXPECT_TRUE(controller.GetPendingEntry());
3943 EXPECT_EQ(1, controller.GetEntryCount());
3945 // Try to commit the pending entry.
3946 main_test_rfh()->SendNavigate(2, url3);
3947 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3948 EXPECT_FALSE(controller.GetPendingEntry());
3949 EXPECT_EQ(2, controller.GetEntryCount());
3950 EXPECT_EQ(url3, controller.GetEntryAtIndex(1)->GetURL());
3953 // Test to ensure that when we do a history navigation back to the current
3954 // committed page (e.g., going forward to a slow-loading page, then pressing
3955 // the back button), we just stop the navigation to prevent the throbber from
3956 // running continuously. Otherwise, the RenderViewHost forces the throbber to
3957 // start, but WebKit essentially ignores the navigation and never sends a
3958 // message to stop the throbber.
3959 TEST_F(NavigationControllerTest, StopOnHistoryNavigationToCurrentPage) {
3960 NavigationControllerImpl& controller = controller_impl();
3961 const GURL url0("http://foo/0");
3962 const GURL url1("http://foo/1");
3964 NavigateAndCommit(url0);
3965 NavigateAndCommit(url1);
3967 // Go back to the original page, then forward to the slow page, then back
3968 controller.GoBack();
3969 contents()->CommitPendingNavigation();
3971 controller.GoForward();
3972 EXPECT_EQ(1, controller.GetPendingEntryIndex());
3974 controller.GoBack();
3975 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3978 TEST_F(NavigationControllerTest, IsInitialNavigation) {
3979 NavigationControllerImpl& controller = controller_impl();
3980 TestNotificationTracker notifications;
3981 RegisterForAllNavNotifications(&notifications, &controller);
3983 // Initial state.
3984 EXPECT_TRUE(controller.IsInitialNavigation());
3986 // After commit, it stays false.
3987 const GURL url1("http://foo1");
3988 main_test_rfh()->SendNavigate(0, url1);
3989 EXPECT_EQ(1U, navigation_entry_committed_counter_);
3990 navigation_entry_committed_counter_ = 0;
3991 EXPECT_FALSE(controller.IsInitialNavigation());
3993 // After starting a new navigation, it stays false.
3994 const GURL url2("http://foo2");
3995 controller.LoadURL(
3996 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
3999 // Check that the favicon is not reused across a client redirect.
4000 // (crbug.com/28515)
4001 TEST_F(NavigationControllerTest, ClearFaviconOnRedirect) {
4002 const GURL kPageWithFavicon("http://withfavicon.html");
4003 const GURL kPageWithoutFavicon("http://withoutfavicon.html");
4004 const GURL kIconURL("http://withfavicon.ico");
4005 const gfx::Image kDefaultFavicon = FaviconStatus().image;
4007 NavigationControllerImpl& controller = controller_impl();
4008 TestNotificationTracker notifications;
4009 RegisterForAllNavNotifications(&notifications, &controller);
4011 main_test_rfh()->SendNavigate(0, kPageWithFavicon);
4012 EXPECT_EQ(1U, navigation_entry_committed_counter_);
4013 navigation_entry_committed_counter_ = 0;
4015 NavigationEntry* entry = controller.GetLastCommittedEntry();
4016 EXPECT_TRUE(entry);
4017 EXPECT_EQ(kPageWithFavicon, entry->GetURL());
4019 // Simulate Chromium having set the favicon for |kPageWithFavicon|.
4020 content::FaviconStatus& favicon_status = entry->GetFavicon();
4021 favicon_status.image = CreateImage(SK_ColorWHITE);
4022 favicon_status.url = kIconURL;
4023 favicon_status.valid = true;
4024 EXPECT_FALSE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image));
4026 main_test_rfh()->SendNavigateWithTransition(
4027 0, // same page ID.
4028 kPageWithoutFavicon,
4029 PAGE_TRANSITION_CLIENT_REDIRECT);
4030 EXPECT_EQ(1U, navigation_entry_committed_counter_);
4031 navigation_entry_committed_counter_ = 0;
4033 entry = controller.GetLastCommittedEntry();
4034 EXPECT_TRUE(entry);
4035 EXPECT_EQ(kPageWithoutFavicon, entry->GetURL());
4037 EXPECT_TRUE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image));
4040 // Check that the favicon is not cleared for NavigationEntries which were
4041 // previously navigated to.
4042 TEST_F(NavigationControllerTest, BackNavigationDoesNotClearFavicon) {
4043 const GURL kUrl1("http://www.a.com/1");
4044 const GURL kUrl2("http://www.a.com/2");
4045 const GURL kIconURL("http://www.a.com/1/favicon.ico");
4047 NavigationControllerImpl& controller = controller_impl();
4048 TestNotificationTracker notifications;
4049 RegisterForAllNavNotifications(&notifications, &controller);
4051 main_test_rfh()->SendNavigate(0, kUrl1);
4052 EXPECT_EQ(1U, navigation_entry_committed_counter_);
4053 navigation_entry_committed_counter_ = 0;
4055 // Simulate Chromium having set the favicon for |kUrl1|.
4056 gfx::Image favicon_image = CreateImage(SK_ColorWHITE);
4057 content::NavigationEntry* entry = controller.GetLastCommittedEntry();
4058 EXPECT_TRUE(entry);
4059 content::FaviconStatus& favicon_status = entry->GetFavicon();
4060 favicon_status.image = favicon_image;
4061 favicon_status.url = kIconURL;
4062 favicon_status.valid = true;
4064 // Navigate to another page and go back to the original page.
4065 main_test_rfh()->SendNavigate(1, kUrl2);
4066 EXPECT_EQ(1U, navigation_entry_committed_counter_);
4067 navigation_entry_committed_counter_ = 0;
4068 main_test_rfh()->SendNavigateWithTransition(
4070 kUrl1,
4071 PAGE_TRANSITION_FORWARD_BACK);
4072 EXPECT_EQ(1U, navigation_entry_committed_counter_);
4073 navigation_entry_committed_counter_ = 0;
4075 // Verify that the favicon for the page at |kUrl1| was not cleared.
4076 entry = controller.GetEntryAtIndex(0);
4077 EXPECT_TRUE(entry);
4078 EXPECT_EQ(kUrl1, entry->GetURL());
4079 EXPECT_TRUE(DoImagesMatch(favicon_image, entry->GetFavicon().image));
4082 // The test crashes on android: http://crbug.com/170449
4083 #if defined(OS_ANDROID)
4084 #define MAYBE_PurgeScreenshot DISABLED_PurgeScreenshot
4085 #else
4086 #define MAYBE_PurgeScreenshot PurgeScreenshot
4087 #endif
4088 // Tests that screenshot are purged correctly.
4089 TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
4090 NavigationControllerImpl& controller = controller_impl();
4092 NavigationEntryImpl* entry;
4094 // Navigate enough times to make sure that some screenshots are purged.
4095 for (int i = 0; i < 12; ++i) {
4096 const GURL url(base::StringPrintf("http://foo%d/", i));
4097 NavigateAndCommit(url);
4098 EXPECT_EQ(i, controller.GetCurrentEntryIndex());
4101 MockScreenshotManager* screenshot_manager =
4102 new MockScreenshotManager(&controller);
4103 controller.SetScreenshotManager(screenshot_manager);
4104 for (int i = 0; i < controller.GetEntryCount(); ++i) {
4105 entry = NavigationEntryImpl::FromNavigationEntry(
4106 controller.GetEntryAtIndex(i));
4107 screenshot_manager->TakeScreenshotFor(entry);
4108 EXPECT_TRUE(entry->screenshot().get());
4111 NavigateAndCommit(GURL("https://foo/"));
4112 EXPECT_EQ(13, controller.GetEntryCount());
4113 entry = NavigationEntryImpl::FromNavigationEntry(
4114 controller.GetEntryAtIndex(11));
4115 screenshot_manager->TakeScreenshotFor(entry);
4117 for (int i = 0; i < 2; ++i) {
4118 entry = NavigationEntryImpl::FromNavigationEntry(
4119 controller.GetEntryAtIndex(i));
4120 EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
4121 << " not purged";
4124 for (int i = 2; i < controller.GetEntryCount() - 1; ++i) {
4125 entry = NavigationEntryImpl::FromNavigationEntry(
4126 controller.GetEntryAtIndex(i));
4127 EXPECT_TRUE(entry->screenshot().get()) << "Screenshot not found for " << i;
4130 // Navigate to index 5 and then try to assign screenshot to all entries.
4131 controller.GoToIndex(5);
4132 contents()->CommitPendingNavigation();
4133 EXPECT_EQ(5, controller.GetCurrentEntryIndex());
4134 for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
4135 entry = NavigationEntryImpl::FromNavigationEntry(
4136 controller.GetEntryAtIndex(i));
4137 screenshot_manager->TakeScreenshotFor(entry);
4140 for (int i = 10; i <= 12; ++i) {
4141 entry = NavigationEntryImpl::FromNavigationEntry(
4142 controller.GetEntryAtIndex(i));
4143 EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
4144 << " not purged";
4145 screenshot_manager->TakeScreenshotFor(entry);
4148 // Navigate to index 7 and assign screenshot to all entries.
4149 controller.GoToIndex(7);
4150 contents()->CommitPendingNavigation();
4151 EXPECT_EQ(7, controller.GetCurrentEntryIndex());
4152 for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
4153 entry = NavigationEntryImpl::FromNavigationEntry(
4154 controller.GetEntryAtIndex(i));
4155 screenshot_manager->TakeScreenshotFor(entry);
4158 for (int i = 0; i < 2; ++i) {
4159 entry = NavigationEntryImpl::FromNavigationEntry(
4160 controller.GetEntryAtIndex(i));
4161 EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
4162 << " not purged";
4165 // Clear all screenshots.
4166 EXPECT_EQ(13, controller.GetEntryCount());
4167 EXPECT_EQ(10, screenshot_manager->GetScreenshotCount());
4168 controller.ClearAllScreenshots();
4169 EXPECT_EQ(0, screenshot_manager->GetScreenshotCount());
4170 for (int i = 0; i < controller.GetEntryCount(); ++i) {
4171 entry = NavigationEntryImpl::FromNavigationEntry(
4172 controller.GetEntryAtIndex(i));
4173 EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
4174 << " not cleared";
4178 // Test that the navigation controller clears its session history when a
4179 // navigation commits with the clear history list flag set.
4180 TEST_F(NavigationControllerTest, ClearHistoryList) {
4181 const GURL url1("http://foo1");
4182 const GURL url2("http://foo2");
4183 const GURL url3("http://foo3");
4184 const GURL url4("http://foo4");
4186 NavigationControllerImpl& controller = controller_impl();
4188 // Create a session history with three entries, second entry is active.
4189 NavigateAndCommit(url1);
4190 NavigateAndCommit(url2);
4191 NavigateAndCommit(url3);
4192 controller.GoBack();
4193 contents()->CommitPendingNavigation();
4194 EXPECT_EQ(3, controller.GetEntryCount());
4195 EXPECT_EQ(1, controller.GetCurrentEntryIndex());
4197 // Create a new pending navigation, and indicate that the session history
4198 // should be cleared.
4199 NavigationController::LoadURLParams params(url4);
4200 params.should_clear_history_list = true;
4201 controller.LoadURLWithParams(params);
4203 // Verify that the pending entry correctly indicates that the session history
4204 // should be cleared.
4205 NavigationEntryImpl* entry =
4206 NavigationEntryImpl::FromNavigationEntry(
4207 controller.GetPendingEntry());
4208 ASSERT_TRUE(entry);
4209 EXPECT_TRUE(entry->should_clear_history_list());
4211 // Assume that the RV correctly cleared its history and commit the navigation.
4212 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost())->
4213 set_simulate_history_list_was_cleared(true);
4214 contents()->CommitPendingNavigation();
4216 // Verify that the NavigationController's session history was correctly
4217 // cleared.
4218 EXPECT_EQ(1, controller.GetEntryCount());
4219 EXPECT_EQ(0, controller.GetCurrentEntryIndex());
4220 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
4221 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
4222 EXPECT_FALSE(controller.CanGoBack());
4223 EXPECT_FALSE(controller.CanGoForward());
4224 EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
4227 } // namespace content