blob: c86e3a5dc4eb9be3eca162608999d8daf199c4ed [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
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"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010011#include "base/strings/string_util.h"
12#include "base/strings/utf_string_conversions.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010013#include "base/time/time.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000014// These are only used for commented out tests. If someone wants to enable
15// them, they should be moved to chrome first.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000016// #include "chrome/browser/history/history_service.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000017// #include "chrome/browser/profiles/profile_manager.h"
18// #include "chrome/browser/sessions/session_service.h"
19// #include "chrome/browser/sessions/session_service_factory.h"
20// #include "chrome/browser/sessions/session_service_test_helper.h"
21// #include "chrome/browser/sessions/session_types.h"
22#include "content/browser/renderer_host/test_render_view_host.h"
23#include "content/browser/site_instance_impl.h"
24#include "content/browser/web_contents/navigation_controller_impl.h"
25#include "content/browser/web_contents/navigation_entry_impl.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000026#include "content/browser/web_contents/web_contents_impl.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010027#include "content/browser/web_contents/web_contents_screenshot_manager.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000028#include "content/common/view_messages.h"
29#include "content/public/browser/navigation_details.h"
30#include "content/public/browser/notification_registrar.h"
31#include "content/public/browser/notification_types.h"
32#include "content/public/browser/render_view_host.h"
33#include "content/public/browser/render_view_host_observer.h"
34#include "content/public/browser/web_contents_delegate.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010035#include "content/public/browser/web_contents_observer.h"
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010036#include "content/public/common/page_state.h"
Ben Murdoch2385ea32013-08-06 11:01:04 +010037#include "content/public/common/url_constants.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000038#include "content/public/test/mock_render_process_host.h"
39#include "content/public/test/test_notification_tracker.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010040#include "content/public/test/test_utils.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000041#include "content/test/test_web_contents.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000042#include "net/base/net_util.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000043#include "skia/ext/platform_canvas.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000044#include "testing/gtest/include/gtest/gtest.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000045
46using base::Time;
47
48namespace {
49
50// Creates an image with a 1x1 SkBitmap of the specified |color|.
51gfx::Image CreateImage(SkColor color) {
52 SkBitmap bitmap;
53 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
54 bitmap.allocPixels();
55 bitmap.eraseColor(color);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000056 return gfx::Image::CreateFrom1xBitmap(bitmap);
Torne (Richard Coles)58218062012-11-14 11:43:16 +000057}
58
59// Returns true if images |a| and |b| have the same pixel data.
60bool DoImagesMatch(const gfx::Image& a, const gfx::Image& b) {
61 // Assume that if the 1x bitmaps match, the images match.
62 SkBitmap a_bitmap = a.AsBitmap();
63 SkBitmap b_bitmap = b.AsBitmap();
64
65 if (a_bitmap.width() != b_bitmap.width() ||
66 a_bitmap.height() != b_bitmap.height()) {
67 return false;
68 }
69 SkAutoLockPixels a_bitmap_lock(a_bitmap);
70 SkAutoLockPixels b_bitmap_lock(b_bitmap);
71 return memcmp(a_bitmap.getPixels(),
72 b_bitmap.getPixels(),
73 a_bitmap.getSize()) == 0;
74}
75
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010076class MockScreenshotManager : public content::WebContentsScreenshotManager {
77 public:
78 explicit MockScreenshotManager(content::NavigationControllerImpl* owner)
79 : content::WebContentsScreenshotManager(owner),
80 encoding_screenshot_in_progress_(false) {
81 }
82
83 virtual ~MockScreenshotManager() {
84 }
85
86 void TakeScreenshotFor(content::NavigationEntryImpl* entry) {
87 SkBitmap bitmap;
88 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
89 bitmap.allocPixels();
90 bitmap.eraseRGB(0, 0, 0);
91 encoding_screenshot_in_progress_ = true;
92 OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
93 WaitUntilScreenshotIsReady();
94 }
95
96 int GetScreenshotCount() {
97 return content::WebContentsScreenshotManager::GetScreenshotCount();
98 }
99
100 void WaitUntilScreenshotIsReady() {
101 if (!encoding_screenshot_in_progress_)
102 return;
103 message_loop_runner_ = new content::MessageLoopRunner;
104 message_loop_runner_->Run();
105 }
106
107 private:
108 // Overridden from content::WebContentsScreenshotManager:
109 virtual void TakeScreenshotImpl(
110 content::RenderViewHost* host,
111 content::NavigationEntryImpl* entry) OVERRIDE {
112 }
113
114 virtual void OnScreenshotSet(content::NavigationEntryImpl* entry) OVERRIDE {
115 encoding_screenshot_in_progress_ = false;
116 WebContentsScreenshotManager::OnScreenshotSet(entry);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100117 if (message_loop_runner_.get())
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100118 message_loop_runner_->Quit();
119 }
120
121 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
122 bool encoding_screenshot_in_progress_;
123
124 DISALLOW_COPY_AND_ASSIGN(MockScreenshotManager);
125};
126
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000127} // namespace
128
129namespace content {
130
131// TimeSmoother tests ----------------------------------------------------------
132
133// With no duplicates, GetSmoothedTime should be the identity
134// function.
135TEST(TimeSmoother, Basic) {
136 NavigationControllerImpl::TimeSmoother smoother;
137 for (int64 i = 1; i < 1000; ++i) {
138 base::Time t = base::Time::FromInternalValue(i);
139 EXPECT_EQ(t, smoother.GetSmoothedTime(t));
140 }
141}
142
143// With a single duplicate and timestamps thereafter increasing by one
144// microsecond, the smoothed time should always be one behind.
145TEST(TimeSmoother, SingleDuplicate) {
146 NavigationControllerImpl::TimeSmoother smoother;
147 base::Time t = base::Time::FromInternalValue(1);
148 EXPECT_EQ(t, smoother.GetSmoothedTime(t));
149 for (int64 i = 1; i < 1000; ++i) {
150 base::Time expected_t = base::Time::FromInternalValue(i + 1);
151 t = base::Time::FromInternalValue(i);
152 EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
153 }
154}
155
156// With k duplicates and timestamps thereafter increasing by one
157// microsecond, the smoothed time should always be k behind.
158TEST(TimeSmoother, ManyDuplicates) {
159 const int64 kNumDuplicates = 100;
160 NavigationControllerImpl::TimeSmoother smoother;
161 base::Time t = base::Time::FromInternalValue(1);
162 for (int64 i = 0; i < kNumDuplicates; ++i) {
163 base::Time expected_t = base::Time::FromInternalValue(i + 1);
164 EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
165 }
166 for (int64 i = 1; i < 1000; ++i) {
167 base::Time expected_t =
168 base::Time::FromInternalValue(i + kNumDuplicates);
169 t = base::Time::FromInternalValue(i);
170 EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
171 }
172}
173
174// If the clock jumps far back enough after a run of duplicates, it
175// should immediately jump to that value.
176TEST(TimeSmoother, ClockBackwardsJump) {
177 const int64 kNumDuplicates = 100;
178 NavigationControllerImpl::TimeSmoother smoother;
179 base::Time t = base::Time::FromInternalValue(1000);
180 for (int64 i = 0; i < kNumDuplicates; ++i) {
181 base::Time expected_t = base::Time::FromInternalValue(i + 1000);
182 EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t));
183 }
184 t = base::Time::FromInternalValue(500);
185 EXPECT_EQ(t, smoother.GetSmoothedTime(t));
186}
187
188// NavigationControllerTest ----------------------------------------------------
189
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100190class NavigationControllerTest
191 : public RenderViewHostImplTestHarness,
192 public WebContentsObserver {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000193 public:
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100194 NavigationControllerTest() : navigation_entry_committed_counter_(0) {
195 }
196
197 virtual void SetUp() OVERRIDE {
198 RenderViewHostImplTestHarness::SetUp();
199 WebContents* web_contents = RenderViewHostImplTestHarness::web_contents();
200 ASSERT_TRUE(web_contents); // The WebContents should be created by now.
201 WebContentsObserver::Observe(web_contents);
202 }
203
204 // WebContentsObserver:
205 virtual void NavigationEntryCommitted(
206 const LoadCommittedDetails& load_details) OVERRIDE {
207 navigation_entry_committed_counter_++;
208 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000209
210 NavigationControllerImpl& controller_impl() {
211 return static_cast<NavigationControllerImpl&>(controller());
212 }
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100213
214 protected:
215 size_t navigation_entry_committed_counter_;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000216};
217
218void RegisterForAllNavNotifications(TestNotificationTracker* tracker,
219 NavigationController* controller) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000220 tracker->ListenFor(NOTIFICATION_NAV_LIST_PRUNED,
221 Source<NavigationController>(controller));
222 tracker->ListenFor(NOTIFICATION_NAV_ENTRY_CHANGED,
223 Source<NavigationController>(controller));
224}
225
226SiteInstance* GetSiteInstanceFromEntry(NavigationEntry* entry) {
227 return NavigationEntryImpl::FromNavigationEntry(entry)->site_instance();
228}
229
230class TestWebContentsDelegate : public WebContentsDelegate {
231 public:
232 explicit TestWebContentsDelegate() :
233 navigation_state_change_count_(0) {}
234
235 int navigation_state_change_count() {
236 return navigation_state_change_count_;
237 }
238
239 // Keep track of whether the tab has notified us of a navigation state change.
240 virtual void NavigationStateChanged(const WebContents* source,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000241 unsigned changed_flags) OVERRIDE {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000242 navigation_state_change_count_++;
243 }
244
245 private:
246 // The number of times NavigationStateChanged has been called.
247 int navigation_state_change_count_;
248};
249
250// -----------------------------------------------------------------------------
251
252TEST_F(NavigationControllerTest, Defaults) {
253 NavigationControllerImpl& controller = controller_impl();
254
255 EXPECT_FALSE(controller.GetPendingEntry());
256 EXPECT_FALSE(controller.GetActiveEntry());
257 EXPECT_FALSE(controller.GetVisibleEntry());
258 EXPECT_FALSE(controller.GetLastCommittedEntry());
259 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
260 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
261 EXPECT_EQ(controller.GetEntryCount(), 0);
262 EXPECT_FALSE(controller.CanGoBack());
263 EXPECT_FALSE(controller.CanGoForward());
264}
265
266TEST_F(NavigationControllerTest, GoToOffset) {
267 NavigationControllerImpl& controller = controller_impl();
268 TestNotificationTracker notifications;
269 RegisterForAllNavNotifications(&notifications, &controller);
270
271 const int kNumUrls = 5;
272 std::vector<GURL> urls(kNumUrls);
273 for (int i = 0; i < kNumUrls; ++i) {
274 urls[i] = GURL(base::StringPrintf("http://www.a.com/%d", i));
275 }
276
277 test_rvh()->SendNavigate(0, urls[0]);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100278 EXPECT_EQ(1U, navigation_entry_committed_counter_);
279 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000280 EXPECT_EQ(urls[0], controller.GetActiveEntry()->GetVirtualURL());
281 EXPECT_FALSE(controller.CanGoBack());
282 EXPECT_FALSE(controller.CanGoForward());
283 EXPECT_FALSE(controller.CanGoToOffset(1));
284
285 for (int i = 1; i <= 4; ++i) {
286 test_rvh()->SendNavigate(i, urls[i]);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100287 EXPECT_EQ(1U, navigation_entry_committed_counter_);
288 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000289 EXPECT_EQ(urls[i], controller.GetActiveEntry()->GetVirtualURL());
290 EXPECT_TRUE(controller.CanGoToOffset(-i));
291 EXPECT_FALSE(controller.CanGoToOffset(-(i + 1)));
292 EXPECT_FALSE(controller.CanGoToOffset(1));
293 }
294
295 // We have loaded 5 pages, and are currently at the last-loaded page.
296 int url_index = 4;
297
298 enum Tests {
299 GO_TO_MIDDLE_PAGE = -2,
300 GO_FORWARDS = 1,
301 GO_BACKWARDS = -1,
302 GO_TO_BEGINNING = -2,
303 GO_TO_END = 4,
304 NUM_TESTS = 5,
305 };
306
307 const int test_offsets[NUM_TESTS] = {
308 GO_TO_MIDDLE_PAGE,
309 GO_FORWARDS,
310 GO_BACKWARDS,
311 GO_TO_BEGINNING,
312 GO_TO_END
313 };
314
315 for (int test = 0; test < NUM_TESTS; ++test) {
316 int offset = test_offsets[test];
317 controller.GoToOffset(offset);
318 url_index += offset;
319 // Check that the GoToOffset will land on the expected page.
320 EXPECT_EQ(urls[url_index], controller.GetPendingEntry()->GetVirtualURL());
321 test_rvh()->SendNavigate(url_index, urls[url_index]);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100322 EXPECT_EQ(1U, navigation_entry_committed_counter_);
323 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000324 // Check that we can go to any valid offset into the history.
325 for (size_t j = 0; j < urls.size(); ++j)
326 EXPECT_TRUE(controller.CanGoToOffset(j - url_index));
327 // Check that we can't go beyond the beginning or end of the history.
328 EXPECT_FALSE(controller.CanGoToOffset(-(url_index + 1)));
329 EXPECT_FALSE(controller.CanGoToOffset(urls.size() - url_index));
330 }
331}
332
333TEST_F(NavigationControllerTest, LoadURL) {
334 NavigationControllerImpl& controller = controller_impl();
335 TestNotificationTracker notifications;
336 RegisterForAllNavNotifications(&notifications, &controller);
337
338 const GURL url1("http://foo1");
339 const GURL url2("http://foo2");
340
341 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
342 // Creating a pending notification should not have issued any of the
343 // notifications we're listening for.
344 EXPECT_EQ(0U, notifications.size());
345
346 // The load should now be pending.
347 EXPECT_EQ(controller.GetEntryCount(), 0);
348 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
349 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
350 EXPECT_FALSE(controller.GetLastCommittedEntry());
351 ASSERT_TRUE(controller.GetPendingEntry());
352 EXPECT_EQ(controller.GetPendingEntry(), controller.GetActiveEntry());
353 EXPECT_EQ(controller.GetPendingEntry(), controller.GetVisibleEntry());
354 EXPECT_FALSE(controller.CanGoBack());
355 EXPECT_FALSE(controller.CanGoForward());
356 EXPECT_EQ(contents()->GetMaxPageID(), -1);
357
358 // The timestamp should not have been set yet.
359 EXPECT_TRUE(controller.GetPendingEntry()->GetTimestamp().is_null());
360
361 // We should have gotten no notifications from the preceeding checks.
362 EXPECT_EQ(0U, notifications.size());
363
364 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100365 EXPECT_EQ(1U, navigation_entry_committed_counter_);
366 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000367
368 // The load should now be committed.
369 EXPECT_EQ(controller.GetEntryCount(), 1);
370 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
371 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
372 EXPECT_TRUE(controller.GetLastCommittedEntry());
373 EXPECT_FALSE(controller.GetPendingEntry());
374 ASSERT_TRUE(controller.GetActiveEntry());
375 EXPECT_EQ(controller.GetActiveEntry(), controller.GetVisibleEntry());
376 EXPECT_FALSE(controller.CanGoBack());
377 EXPECT_FALSE(controller.CanGoForward());
378 EXPECT_EQ(contents()->GetMaxPageID(), 0);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000379 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
380 controller.GetLastCommittedEntry())->bindings());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000381
382 // The timestamp should have been set.
383 EXPECT_FALSE(controller.GetActiveEntry()->GetTimestamp().is_null());
384
385 // Load another...
386 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
387
388 // The load should now be pending.
389 EXPECT_EQ(controller.GetEntryCount(), 1);
390 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
391 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
392 EXPECT_TRUE(controller.GetLastCommittedEntry());
393 ASSERT_TRUE(controller.GetPendingEntry());
394 EXPECT_EQ(controller.GetPendingEntry(), controller.GetActiveEntry());
395 EXPECT_EQ(controller.GetPendingEntry(), controller.GetVisibleEntry());
396 // TODO(darin): maybe this should really be true?
397 EXPECT_FALSE(controller.CanGoBack());
398 EXPECT_FALSE(controller.CanGoForward());
399 EXPECT_EQ(contents()->GetMaxPageID(), 0);
400
401 EXPECT_TRUE(controller.GetPendingEntry()->GetTimestamp().is_null());
402
403 // Simulate the beforeunload ack for the cross-site transition, and then the
404 // commit.
405 test_rvh()->SendShouldCloseACK(true);
406 static_cast<TestRenderViewHost*>(
407 contents()->GetPendingRenderViewHost())->SendNavigate(1, url2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100408 EXPECT_EQ(1U, navigation_entry_committed_counter_);
409 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000410
411 // The load should now be committed.
412 EXPECT_EQ(controller.GetEntryCount(), 2);
413 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
414 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
415 EXPECT_TRUE(controller.GetLastCommittedEntry());
416 EXPECT_FALSE(controller.GetPendingEntry());
417 ASSERT_TRUE(controller.GetActiveEntry());
418 EXPECT_EQ(controller.GetActiveEntry(), controller.GetVisibleEntry());
419 EXPECT_TRUE(controller.CanGoBack());
420 EXPECT_FALSE(controller.CanGoForward());
421 EXPECT_EQ(contents()->GetMaxPageID(), 1);
422
423 EXPECT_FALSE(controller.GetActiveEntry()->GetTimestamp().is_null());
424}
425
426namespace {
427
428base::Time GetFixedTime(base::Time time) {
429 return time;
430}
431
432} // namespace
433
434TEST_F(NavigationControllerTest, LoadURLSameTime) {
435 NavigationControllerImpl& controller = controller_impl();
436 TestNotificationTracker notifications;
437 RegisterForAllNavNotifications(&notifications, &controller);
438
439 // Set the clock to always return a timestamp of 1.
440 controller.SetGetTimestampCallbackForTest(
441 base::Bind(&GetFixedTime, base::Time::FromInternalValue(1)));
442
443 const GURL url1("http://foo1");
444 const GURL url2("http://foo2");
445
446 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
447
448 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100449 EXPECT_EQ(1U, navigation_entry_committed_counter_);
450 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000451
452 // Load another...
453 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
454
455 // Simulate the beforeunload ack for the cross-site transition, and then the
456 // commit.
457 test_rvh()->SendShouldCloseACK(true);
458 test_rvh()->SendNavigate(1, url2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100459 EXPECT_EQ(1U, navigation_entry_committed_counter_);
460 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000461
462 // The two loads should now be committed.
463 ASSERT_EQ(controller.GetEntryCount(), 2);
464
465 // Timestamps should be distinct despite the clock returning the
466 // same value.
467 EXPECT_EQ(1u,
468 controller.GetEntryAtIndex(0)->GetTimestamp().ToInternalValue());
469 EXPECT_EQ(2u,
470 controller.GetEntryAtIndex(1)->GetTimestamp().ToInternalValue());
471}
472
473void CheckNavigationEntryMatchLoadParams(
474 NavigationController::LoadURLParams& load_params,
475 NavigationEntryImpl* entry) {
476 EXPECT_EQ(load_params.url, entry->GetURL());
477 EXPECT_EQ(load_params.referrer.url, entry->GetReferrer().url);
478 EXPECT_EQ(load_params.referrer.policy, entry->GetReferrer().policy);
479 EXPECT_EQ(load_params.transition_type, entry->GetTransitionType());
480 EXPECT_EQ(load_params.extra_headers, entry->extra_headers());
481
482 EXPECT_EQ(load_params.is_renderer_initiated, entry->is_renderer_initiated());
483 EXPECT_EQ(load_params.base_url_for_data_url, entry->GetBaseURLForDataURL());
484 if (!load_params.virtual_url_for_data_url.is_empty()) {
485 EXPECT_EQ(load_params.virtual_url_for_data_url, entry->GetVirtualURL());
486 }
487 if (NavigationController::UA_OVERRIDE_INHERIT !=
488 load_params.override_user_agent) {
489 bool should_override = (NavigationController::UA_OVERRIDE_TRUE ==
490 load_params.override_user_agent);
491 EXPECT_EQ(should_override, entry->GetIsOverridingUserAgent());
492 }
493 EXPECT_EQ(load_params.browser_initiated_post_data,
494 entry->GetBrowserInitiatedPostData());
495 EXPECT_EQ(load_params.transferred_global_request_id,
496 entry->transferred_global_request_id());
497}
498
499TEST_F(NavigationControllerTest, LoadURLWithParams) {
500 NavigationControllerImpl& controller = controller_impl();
501
502 NavigationController::LoadURLParams load_params(GURL("http://foo"));
503 load_params.referrer =
504 Referrer(GURL("http://referrer"), WebKit::WebReferrerPolicyDefault);
505 load_params.transition_type = PAGE_TRANSITION_GENERATED;
506 load_params.extra_headers = "content-type: text/plain";
507 load_params.load_type = NavigationController::LOAD_TYPE_DEFAULT;
508 load_params.is_renderer_initiated = true;
509 load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
Ben Murdoch2385ea32013-08-06 11:01:04 +0100510 load_params.transferred_global_request_id = GlobalRequestID(2, 3);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000511
512 controller.LoadURLWithParams(load_params);
513 NavigationEntryImpl* entry =
514 NavigationEntryImpl::FromNavigationEntry(
515 controller.GetPendingEntry());
516
517 // The timestamp should not have been set yet.
518 ASSERT_TRUE(entry);
519 EXPECT_TRUE(entry->GetTimestamp().is_null());
520
521 CheckNavigationEntryMatchLoadParams(load_params, entry);
522}
523
524TEST_F(NavigationControllerTest, LoadURLWithExtraParams_Data) {
525 NavigationControllerImpl& controller = controller_impl();
526
527 NavigationController::LoadURLParams load_params(
528 GURL("data:text/html,dataurl"));
529 load_params.load_type = NavigationController::LOAD_TYPE_DATA;
530 load_params.base_url_for_data_url = GURL("http://foo");
Ben Murdoch2385ea32013-08-06 11:01:04 +0100531 load_params.virtual_url_for_data_url = GURL(kAboutBlankURL);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000532 load_params.override_user_agent = NavigationController::UA_OVERRIDE_FALSE;
533
534 controller.LoadURLWithParams(load_params);
535 NavigationEntryImpl* entry =
536 NavigationEntryImpl::FromNavigationEntry(
537 controller.GetPendingEntry());
538
539 CheckNavigationEntryMatchLoadParams(load_params, entry);
540}
541
542TEST_F(NavigationControllerTest, LoadURLWithExtraParams_HttpPost) {
543 NavigationControllerImpl& controller = controller_impl();
544
545 NavigationController::LoadURLParams load_params(GURL("https://posturl"));
546 load_params.transition_type = PAGE_TRANSITION_TYPED;
547 load_params.load_type =
548 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
549 load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
550
551
552 const unsigned char* raw_data =
553 reinterpret_cast<const unsigned char*>("d\n\0a2");
554 const int length = 5;
555 std::vector<unsigned char> post_data_vector(raw_data, raw_data+length);
556 scoped_refptr<base::RefCountedBytes> data =
557 base::RefCountedBytes::TakeVector(&post_data_vector);
558 load_params.browser_initiated_post_data = data.get();
559
560 controller.LoadURLWithParams(load_params);
561 NavigationEntryImpl* entry =
562 NavigationEntryImpl::FromNavigationEntry(
563 controller.GetPendingEntry());
564
565 CheckNavigationEntryMatchLoadParams(load_params, entry);
566}
567
568// Tests what happens when the same page is loaded again. Should not create a
569// new session history entry. This is what happens when you press enter in the
570// URL bar to reload: a pending entry is created and then it is discarded when
571// the load commits (because WebCore didn't actually make a new entry).
572TEST_F(NavigationControllerTest, LoadURL_SamePage) {
573 NavigationControllerImpl& controller = controller_impl();
574 TestNotificationTracker notifications;
575 RegisterForAllNavNotifications(&notifications, &controller);
576
577 const GURL url1("http://foo1");
578
579 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
580 EXPECT_EQ(0U, notifications.size());
581 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100582 EXPECT_EQ(1U, navigation_entry_committed_counter_);
583 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000584
585 ASSERT_TRUE(controller.GetActiveEntry());
586 const base::Time timestamp = controller.GetActiveEntry()->GetTimestamp();
587 EXPECT_FALSE(timestamp.is_null());
588
589 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
590 EXPECT_EQ(0U, notifications.size());
591 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100592 EXPECT_EQ(1U, navigation_entry_committed_counter_);
593 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000594
595 // We should not have produced a new session history entry.
596 EXPECT_EQ(controller.GetEntryCount(), 1);
597 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
598 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
599 EXPECT_TRUE(controller.GetLastCommittedEntry());
600 EXPECT_FALSE(controller.GetPendingEntry());
601 ASSERT_TRUE(controller.GetActiveEntry());
602 EXPECT_FALSE(controller.CanGoBack());
603 EXPECT_FALSE(controller.CanGoForward());
604
605 // The timestamp should have been updated.
606 //
607 // TODO(akalin): Change this EXPECT_GE (and other similar ones) to
608 // EXPECT_GT once we guarantee that timestamps are unique.
609 EXPECT_GE(controller.GetActiveEntry()->GetTimestamp(), timestamp);
610}
611
612// Tests loading a URL but discarding it before the load commits.
613TEST_F(NavigationControllerTest, LoadURL_Discarded) {
614 NavigationControllerImpl& controller = controller_impl();
615 TestNotificationTracker notifications;
616 RegisterForAllNavNotifications(&notifications, &controller);
617
618 const GURL url1("http://foo1");
619 const GURL url2("http://foo2");
620
621 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
622 EXPECT_EQ(0U, notifications.size());
623 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100624 EXPECT_EQ(1U, navigation_entry_committed_counter_);
625 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000626
627 ASSERT_TRUE(controller.GetActiveEntry());
628 const base::Time timestamp = controller.GetActiveEntry()->GetTimestamp();
629 EXPECT_FALSE(timestamp.is_null());
630
631 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
632 controller.DiscardNonCommittedEntries();
633 EXPECT_EQ(0U, notifications.size());
634
635 // Should not have produced a new session history entry.
636 EXPECT_EQ(controller.GetEntryCount(), 1);
637 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
638 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
639 EXPECT_TRUE(controller.GetLastCommittedEntry());
640 EXPECT_FALSE(controller.GetPendingEntry());
641 ASSERT_TRUE(controller.GetActiveEntry());
642 EXPECT_FALSE(controller.CanGoBack());
643 EXPECT_FALSE(controller.CanGoForward());
644
645 // Timestamp should not have changed.
646 EXPECT_EQ(timestamp, controller.GetActiveEntry()->GetTimestamp());
647}
648
649// Tests navigations that come in unrequested. This happens when the user
650// navigates from the web page, and here we test that there is no pending entry.
651TEST_F(NavigationControllerTest, LoadURL_NoPending) {
652 NavigationControllerImpl& controller = controller_impl();
653 TestNotificationTracker notifications;
654 RegisterForAllNavNotifications(&notifications, &controller);
655
656 // First make an existing committed entry.
657 const GURL kExistingURL1("http://eh");
658 controller.LoadURL(
659 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
660 test_rvh()->SendNavigate(0, kExistingURL1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100661 EXPECT_EQ(1U, navigation_entry_committed_counter_);
662 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000663
664 // Do a new navigation without making a pending one.
665 const GURL kNewURL("http://see");
666 test_rvh()->SendNavigate(99, kNewURL);
667
668 // There should no longer be any pending entry, and the third navigation we
669 // just made should be committed.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100670 EXPECT_EQ(1U, navigation_entry_committed_counter_);
671 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000672 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
673 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
674 EXPECT_EQ(kNewURL, controller.GetActiveEntry()->GetURL());
675}
676
677// Tests navigating to a new URL when there is a new pending navigation that is
678// not the one that just loaded. This will happen if the user types in a URL to
679// somewhere slow, and then navigates the current page before the typed URL
680// commits.
681TEST_F(NavigationControllerTest, LoadURL_NewPending) {
682 NavigationControllerImpl& controller = controller_impl();
683 TestNotificationTracker notifications;
684 RegisterForAllNavNotifications(&notifications, &controller);
685
686 // First make an existing committed entry.
687 const GURL kExistingURL1("http://eh");
688 controller.LoadURL(
689 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
690 test_rvh()->SendNavigate(0, kExistingURL1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100691 EXPECT_EQ(1U, navigation_entry_committed_counter_);
692 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000693
694 // Make a pending entry to somewhere new.
695 const GURL kExistingURL2("http://bee");
696 controller.LoadURL(
697 kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
698 EXPECT_EQ(0U, notifications.size());
699
700 // After the beforeunload but before it commits, do a new navigation.
701 test_rvh()->SendShouldCloseACK(true);
702 const GURL kNewURL("http://see");
703 static_cast<TestRenderViewHost*>(
704 contents()->GetPendingRenderViewHost())->SendNavigate(3, kNewURL);
705
706 // There should no longer be any pending entry, and the third navigation we
707 // just made should be committed.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100708 EXPECT_EQ(1U, navigation_entry_committed_counter_);
709 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000710 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
711 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
712 EXPECT_EQ(kNewURL, controller.GetActiveEntry()->GetURL());
713}
714
715// Tests navigating to a new URL when there is a pending back/forward
716// navigation. This will happen if the user hits back, but before that commits,
717// they navigate somewhere new.
718TEST_F(NavigationControllerTest, LoadURL_ExistingPending) {
719 NavigationControllerImpl& controller = controller_impl();
720 TestNotificationTracker notifications;
721 RegisterForAllNavNotifications(&notifications, &controller);
722
723 // First make some history.
724 const GURL kExistingURL1("http://foo/eh");
725 controller.LoadURL(
726 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
727 test_rvh()->SendNavigate(0, kExistingURL1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100728 EXPECT_EQ(1U, navigation_entry_committed_counter_);
729 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000730
731 const GURL kExistingURL2("http://foo/bee");
732 controller.LoadURL(
733 kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
734 test_rvh()->SendNavigate(1, kExistingURL2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100735 EXPECT_EQ(1U, navigation_entry_committed_counter_);
736 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000737
738 // Now make a pending back/forward navigation. The zeroth entry should be
739 // pending.
740 controller.GoBack();
741 EXPECT_EQ(0U, notifications.size());
742 EXPECT_EQ(0, controller.GetPendingEntryIndex());
743 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
744
745 // Before that commits, do a new navigation.
746 const GURL kNewURL("http://foo/see");
747 LoadCommittedDetails details;
748 test_rvh()->SendNavigate(3, kNewURL);
749
750 // There should no longer be any pending entry, and the third navigation we
751 // just made should be committed.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100752 EXPECT_EQ(1U, navigation_entry_committed_counter_);
753 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000754 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
755 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
756 EXPECT_EQ(kNewURL, controller.GetActiveEntry()->GetURL());
757}
758
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000759// Tests navigating to a new URL when there is a pending back/forward
760// navigation to a cross-process, privileged URL. This will happen if the user
761// hits back, but before that commits, they navigate somewhere new.
762TEST_F(NavigationControllerTest, LoadURL_PrivilegedPending) {
763 NavigationControllerImpl& controller = controller_impl();
764 TestNotificationTracker notifications;
765 RegisterForAllNavNotifications(&notifications, &controller);
766
767 // First make some history, starting with a privileged URL.
768 const GURL kExistingURL1("http://privileged");
769 controller.LoadURL(
770 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
771 // Pretend it has bindings so we can tell if we incorrectly copy it.
772 test_rvh()->AllowBindings(2);
773 test_rvh()->SendNavigate(0, kExistingURL1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100774 EXPECT_EQ(1U, navigation_entry_committed_counter_);
775 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000776
777 // Navigate cross-process to a second URL.
778 const GURL kExistingURL2("http://foo/eh");
779 controller.LoadURL(
780 kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
781 test_rvh()->SendShouldCloseACK(true);
782 TestRenderViewHost* foo_rvh = static_cast<TestRenderViewHost*>(
783 contents()->GetPendingRenderViewHost());
784 foo_rvh->SendNavigate(1, kExistingURL2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100785 EXPECT_EQ(1U, navigation_entry_committed_counter_);
786 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000787
788 // Now make a pending back/forward navigation to a privileged entry.
789 // The zeroth entry should be pending.
790 controller.GoBack();
791 foo_rvh->SendShouldCloseACK(true);
792 EXPECT_EQ(0U, notifications.size());
793 EXPECT_EQ(0, controller.GetPendingEntryIndex());
794 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
795 EXPECT_EQ(2, NavigationEntryImpl::FromNavigationEntry(
796 controller.GetPendingEntry())->bindings());
797
798 // Before that commits, do a new navigation.
799 const GURL kNewURL("http://foo/bee");
800 LoadCommittedDetails details;
801 foo_rvh->SendNavigate(3, kNewURL);
802
803 // There should no longer be any pending entry, and the third navigation we
804 // just made should be committed.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100805 EXPECT_EQ(1U, navigation_entry_committed_counter_);
806 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000807 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
808 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
809 EXPECT_EQ(kNewURL, controller.GetActiveEntry()->GetURL());
810 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
811 controller.GetLastCommittedEntry())->bindings());
812}
813
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000814// Tests navigating to an existing URL when there is a pending new navigation.
815// This will happen if the user enters a URL, but before that commits, the
816// current page fires history.back().
817TEST_F(NavigationControllerTest, LoadURL_BackPreemptsPending) {
818 NavigationControllerImpl& controller = controller_impl();
819 TestNotificationTracker notifications;
820 RegisterForAllNavNotifications(&notifications, &controller);
821
822 // First make some history.
823 const GURL kExistingURL1("http://foo/eh");
824 controller.LoadURL(
825 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
826 test_rvh()->SendNavigate(0, kExistingURL1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100827 EXPECT_EQ(1U, navigation_entry_committed_counter_);
828 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000829
830 const GURL kExistingURL2("http://foo/bee");
831 controller.LoadURL(
832 kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
833 test_rvh()->SendNavigate(1, kExistingURL2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100834 EXPECT_EQ(1U, navigation_entry_committed_counter_);
835 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000836
837 // Now make a pending new navigation.
838 const GURL kNewURL("http://foo/see");
839 controller.LoadURL(
840 kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
841 EXPECT_EQ(0U, notifications.size());
842 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
843 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
844
845 // Before that commits, a back navigation from the renderer commits.
846 test_rvh()->SendNavigate(0, kExistingURL1);
847
848 // There should no longer be any pending entry, and the back navigation we
849 // just made should be committed.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100850 EXPECT_EQ(1U, navigation_entry_committed_counter_);
851 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000852 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
853 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
854 EXPECT_EQ(kExistingURL1, controller.GetActiveEntry()->GetURL());
855}
856
857// Tests an ignored navigation when there is a pending new navigation.
858// This will happen if the user enters a URL, but before that commits, the
859// current blank page reloads. See http://crbug.com/77507.
860TEST_F(NavigationControllerTest, LoadURL_IgnorePreemptsPending) {
861 NavigationControllerImpl& controller = controller_impl();
862 TestNotificationTracker notifications;
863 RegisterForAllNavNotifications(&notifications, &controller);
864
865 // Set a WebContentsDelegate to listen for state changes.
866 scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
867 EXPECT_FALSE(contents()->GetDelegate());
868 contents()->SetDelegate(delegate.get());
869
870 // Without any navigations, the renderer starts at about:blank.
Ben Murdoch2385ea32013-08-06 11:01:04 +0100871 const GURL kExistingURL(kAboutBlankURL);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000872
873 // Now make a pending new navigation.
874 const GURL kNewURL("http://eh");
875 controller.LoadURL(
876 kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
877 EXPECT_EQ(0U, notifications.size());
878 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
879 EXPECT_TRUE(controller.GetPendingEntry());
880 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
881 EXPECT_EQ(1, delegate->navigation_state_change_count());
882
883 // Before that commits, a document.write and location.reload can cause the
884 // renderer to send a FrameNavigate with page_id -1.
885 test_rvh()->SendNavigate(-1, kExistingURL);
886
887 // This should clear the pending entry and notify of a navigation state
888 // change, so that we do not keep displaying kNewURL.
889 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
890 EXPECT_FALSE(controller.GetPendingEntry());
891 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
892 EXPECT_EQ(2, delegate->navigation_state_change_count());
893
894 contents()->SetDelegate(NULL);
895}
896
897// Tests that the pending entry state is correct after an abort.
898// We do not want to clear the pending entry, so that the user doesn't
899// lose a typed URL. (See http://crbug.com/9682.)
900TEST_F(NavigationControllerTest, LoadURL_AbortDoesntCancelPending) {
901 NavigationControllerImpl& controller = controller_impl();
902 TestNotificationTracker notifications;
903 RegisterForAllNavNotifications(&notifications, &controller);
904
905 // Set a WebContentsDelegate to listen for state changes.
906 scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
907 EXPECT_FALSE(contents()->GetDelegate());
908 contents()->SetDelegate(delegate.get());
909
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100910 // Start with a pending new navigation.
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000911 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());
919
920 // It may abort before committing, if it's a download or due to a stop or
921 // a new navigation from the user.
922 ViewHostMsg_DidFailProvisionalLoadWithError_Params params;
923 params.frame_id = 1;
924 params.is_main_frame = true;
925 params.error_code = net::ERR_ABORTED;
926 params.error_description = string16();
927 params.url = kNewURL;
928 params.showing_repost_interstitial = false;
929 test_rvh()->OnMessageReceived(
930 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
931 params));
932
933 // This should not clear the pending entry or notify of a navigation state
934 // change, so that we keep displaying kNewURL (until the user clears it).
935 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
936 EXPECT_TRUE(controller.GetPendingEntry());
937 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
938 EXPECT_EQ(1, delegate->navigation_state_change_count());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100939 NavigationEntry* pending_entry = controller.GetPendingEntry();
940
941 // Ensure that a reload keeps the same pending entry.
942 controller.Reload(true);
943 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
944 EXPECT_TRUE(controller.GetPendingEntry());
945 EXPECT_EQ(pending_entry, controller.GetPendingEntry());
946 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000947
948 contents()->SetDelegate(NULL);
949}
950
951// Tests that the pending URL is not visible during a renderer-initiated
952// redirect and abort. See http://crbug.com/83031.
953TEST_F(NavigationControllerTest, LoadURL_RedirectAbortDoesntShowPendingURL) {
954 NavigationControllerImpl& controller = controller_impl();
955 TestNotificationTracker notifications;
956 RegisterForAllNavNotifications(&notifications, &controller);
957
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100958 // First make an existing committed entry.
959 const GURL kExistingURL("http://foo/eh");
960 controller.LoadURL(kExistingURL, content::Referrer(),
961 content::PAGE_TRANSITION_TYPED, std::string());
962 test_rvh()->SendNavigate(0, kExistingURL);
963 EXPECT_EQ(1U, navigation_entry_committed_counter_);
964 navigation_entry_committed_counter_ = 0;
965
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000966 // Set a WebContentsDelegate to listen for state changes.
967 scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
968 EXPECT_FALSE(contents()->GetDelegate());
969 contents()->SetDelegate(delegate.get());
970
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000971 // Now make a pending new navigation, initiated by the renderer.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100972 const GURL kNewURL("http://foo/bee");
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000973 NavigationController::LoadURLParams load_url_params(kNewURL);
974 load_url_params.transition_type = PAGE_TRANSITION_TYPED;
975 load_url_params.is_renderer_initiated = true;
976 controller.LoadURLWithParams(load_url_params);
977 EXPECT_EQ(0U, notifications.size());
978 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
979 EXPECT_TRUE(controller.GetPendingEntry());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100980 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
981 EXPECT_EQ(0, delegate->navigation_state_change_count());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000982
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100983 // The visible entry should be the last committed URL, not the pending one.
984 EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000985
986 // Now the navigation redirects.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100987 const GURL kRedirectURL("http://foo/see");
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000988 test_rvh()->OnMessageReceived(
989 ViewHostMsg_DidRedirectProvisionalLoad(0, // routing_id
990 -1, // pending page_id
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000991 kNewURL, // old url
992 kRedirectURL)); // new url
993
994 // We don't want to change the NavigationEntry's url, in case it cancels.
995 // Prevents regression of http://crbug.com/77786.
996 EXPECT_EQ(kNewURL, controller.GetPendingEntry()->GetURL());
997
998 // It may abort before committing, if it's a download or due to a stop or
999 // a new navigation from the user.
1000 ViewHostMsg_DidFailProvisionalLoadWithError_Params params;
1001 params.frame_id = 1;
1002 params.is_main_frame = true;
1003 params.error_code = net::ERR_ABORTED;
1004 params.error_description = string16();
1005 params.url = kRedirectURL;
1006 params.showing_repost_interstitial = false;
1007 test_rvh()->OnMessageReceived(
1008 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
1009 params));
1010
1011 // This should not clear the pending entry or notify of a navigation state
1012 // change.
1013 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1014 EXPECT_TRUE(controller.GetPendingEntry());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001015 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
1016 EXPECT_EQ(0, delegate->navigation_state_change_count());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001017
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001018 // The visible entry should be the last committed URL, not the pending one,
1019 // so that no spoof is possible.
1020 EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001021
1022 contents()->SetDelegate(NULL);
1023}
1024
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001025// Ensure that NavigationEntries track which bindings their RenderViewHost had
1026// at the time they committed. http://crbug.com/173672.
1027TEST_F(NavigationControllerTest, LoadURL_WithBindings) {
1028 NavigationControllerImpl& controller = controller_impl();
1029 TestNotificationTracker notifications;
1030 RegisterForAllNavNotifications(&notifications, &controller);
1031
1032 const GURL url1("http://foo1");
1033 const GURL url2("http://foo2");
1034
1035 // Navigate to a first, unprivileged URL.
1036 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1037 EXPECT_EQ(NavigationEntryImpl::kInvalidBindings,
1038 NavigationEntryImpl::FromNavigationEntry(
1039 controller.GetPendingEntry())->bindings());
1040
1041 // Commit.
1042 TestRenderViewHost* orig_rvh = static_cast<TestRenderViewHost*>(test_rvh());
1043 orig_rvh->SendNavigate(0, url1);
1044 EXPECT_EQ(controller.GetEntryCount(), 1);
1045 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
1046 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
1047 controller.GetLastCommittedEntry())->bindings());
1048
Ben Murdoch7dbb3d52013-07-17 14:55:54 +01001049 // Manually increase the number of active views in the SiteInstance
1050 // that orig_rvh belongs to, to prevent it from being destroyed when
1051 // it gets swapped out, so that we can reuse orig_rvh when the
1052 // controller goes back.
1053 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
1054 increment_active_view_count();
1055
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001056 // Navigate to a second URL, simulate the beforeunload ack for the cross-site
1057 // transition, and set bindings on the pending RenderViewHost to simulate a
1058 // privileged url.
1059 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1060 orig_rvh->SendShouldCloseACK(true);
1061 contents()->GetPendingRenderViewHost()->AllowBindings(1);
1062 static_cast<TestRenderViewHost*>(
1063 contents()->GetPendingRenderViewHost())->SendNavigate(1, url2);
1064
1065 // The second load should be committed, and bindings should be remembered.
1066 EXPECT_EQ(controller.GetEntryCount(), 2);
1067 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
1068 EXPECT_TRUE(controller.CanGoBack());
1069 EXPECT_EQ(1, NavigationEntryImpl::FromNavigationEntry(
1070 controller.GetLastCommittedEntry())->bindings());
1071
1072 // Going back, the first entry should still appear unprivileged.
1073 controller.GoBack();
1074 orig_rvh->SendNavigate(0, url1);
1075 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
1076 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry(
1077 controller.GetLastCommittedEntry())->bindings());
1078}
1079
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001080TEST_F(NavigationControllerTest, Reload) {
1081 NavigationControllerImpl& controller = controller_impl();
1082 TestNotificationTracker notifications;
1083 RegisterForAllNavNotifications(&notifications, &controller);
1084
1085 const GURL url1("http://foo1");
1086
1087 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1088 EXPECT_EQ(0U, notifications.size());
1089 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001090 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1091 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001092 ASSERT_TRUE(controller.GetActiveEntry());
1093 controller.GetActiveEntry()->SetTitle(ASCIIToUTF16("Title"));
1094 controller.Reload(true);
1095 EXPECT_EQ(0U, notifications.size());
1096
1097 const base::Time timestamp = controller.GetActiveEntry()->GetTimestamp();
1098 EXPECT_FALSE(timestamp.is_null());
1099
1100 // The reload is pending.
1101 EXPECT_EQ(controller.GetEntryCount(), 1);
1102 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1103 EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
1104 EXPECT_TRUE(controller.GetLastCommittedEntry());
1105 EXPECT_TRUE(controller.GetPendingEntry());
1106 EXPECT_FALSE(controller.CanGoBack());
1107 EXPECT_FALSE(controller.CanGoForward());
1108 // Make sure the title has been cleared (will be redrawn just after reload).
1109 // Avoids a stale cached title when the new page being reloaded has no title.
1110 // See http://crbug.com/96041.
1111 EXPECT_TRUE(controller.GetActiveEntry()->GetTitle().empty());
1112
1113 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001114 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1115 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001116
1117 // Now the reload is committed.
1118 EXPECT_EQ(controller.GetEntryCount(), 1);
1119 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1120 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1121 EXPECT_TRUE(controller.GetLastCommittedEntry());
1122 EXPECT_FALSE(controller.GetPendingEntry());
1123 EXPECT_FALSE(controller.CanGoBack());
1124 EXPECT_FALSE(controller.CanGoForward());
1125
1126 // The timestamp should have been updated.
1127 ASSERT_TRUE(controller.GetActiveEntry());
1128 EXPECT_GE(controller.GetActiveEntry()->GetTimestamp(), timestamp);
1129}
1130
1131// Tests what happens when a reload navigation produces a new page.
1132TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) {
1133 NavigationControllerImpl& controller = controller_impl();
1134 TestNotificationTracker notifications;
1135 RegisterForAllNavNotifications(&notifications, &controller);
1136
1137 const GURL url1("http://foo1");
1138 const GURL url2("http://foo2");
1139
1140 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1141 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001142 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1143 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001144
1145 controller.Reload(true);
1146 EXPECT_EQ(0U, notifications.size());
1147
1148 test_rvh()->SendNavigate(1, url2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001149 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1150 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001151
1152 // Now the reload is committed.
1153 EXPECT_EQ(controller.GetEntryCount(), 2);
1154 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1155 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1156 EXPECT_TRUE(controller.GetLastCommittedEntry());
1157 EXPECT_FALSE(controller.GetPendingEntry());
1158 EXPECT_TRUE(controller.CanGoBack());
1159 EXPECT_FALSE(controller.CanGoForward());
1160}
1161
1162class TestNavigationObserver : public RenderViewHostObserver {
1163 public:
Ben Murdoch2385ea32013-08-06 11:01:04 +01001164 explicit TestNavigationObserver(RenderViewHost* render_view_host)
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001165 : RenderViewHostObserver(render_view_host) {
1166 }
1167
1168 const GURL& navigated_url() const {
1169 return navigated_url_;
1170 }
1171
1172 protected:
1173 virtual void Navigate(const GURL& url) OVERRIDE {
1174 navigated_url_ = url;
1175 }
1176
1177 private:
1178 GURL navigated_url_;
1179};
1180
1181#if !defined(OS_ANDROID) // http://crbug.com/157428
1182TEST_F(NavigationControllerTest, ReloadOriginalRequestURL) {
1183 NavigationControllerImpl& controller = controller_impl();
1184 TestNotificationTracker notifications;
1185 RegisterForAllNavNotifications(&notifications, &controller);
1186 TestNavigationObserver observer(test_rvh());
1187
1188 const GURL original_url("http://foo1");
1189 const GURL final_url("http://foo2");
1190
1191 // Load up the original URL, but get redirected.
1192 controller.LoadURL(
1193 original_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1194 EXPECT_EQ(0U, notifications.size());
1195 test_rvh()->SendNavigateWithOriginalRequestURL(0, final_url, original_url);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001196 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1197 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001198
1199 // The NavigationEntry should save both the original URL and the final
1200 // redirected URL.
1201 EXPECT_EQ(original_url, controller.GetActiveEntry()->GetOriginalRequestURL());
1202 EXPECT_EQ(final_url, controller.GetActiveEntry()->GetURL());
1203
1204 // Reload using the original URL.
1205 controller.GetActiveEntry()->SetTitle(ASCIIToUTF16("Title"));
1206 controller.ReloadOriginalRequestURL(false);
1207 EXPECT_EQ(0U, notifications.size());
1208
1209 // The reload is pending. The request should point to the original URL.
1210 EXPECT_EQ(original_url, observer.navigated_url());
1211 EXPECT_EQ(controller.GetEntryCount(), 1);
1212 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1213 EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
1214 EXPECT_TRUE(controller.GetLastCommittedEntry());
1215 EXPECT_TRUE(controller.GetPendingEntry());
1216 EXPECT_FALSE(controller.CanGoBack());
1217 EXPECT_FALSE(controller.CanGoForward());
1218
1219 // Make sure the title has been cleared (will be redrawn just after reload).
1220 // Avoids a stale cached title when the new page being reloaded has no title.
1221 // See http://crbug.com/96041.
1222 EXPECT_TRUE(controller.GetActiveEntry()->GetTitle().empty());
1223
1224 // Send that the navigation has proceeded; say it got redirected again.
1225 test_rvh()->SendNavigate(0, final_url);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001226 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1227 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001228
1229 // Now the reload is committed.
1230 EXPECT_EQ(controller.GetEntryCount(), 1);
1231 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1232 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1233 EXPECT_TRUE(controller.GetLastCommittedEntry());
1234 EXPECT_FALSE(controller.GetPendingEntry());
1235 EXPECT_FALSE(controller.CanGoBack());
1236 EXPECT_FALSE(controller.CanGoForward());
1237}
1238
1239#endif // !defined(OS_ANDROID)
1240
1241// Tests what happens when we navigate back successfully
1242TEST_F(NavigationControllerTest, Back) {
1243 NavigationControllerImpl& controller = controller_impl();
1244 TestNotificationTracker notifications;
1245 RegisterForAllNavNotifications(&notifications, &controller);
1246
1247 const GURL url1("http://foo1");
1248 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001249 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1250 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001251
1252 const GURL url2("http://foo2");
1253 test_rvh()->SendNavigate(1, url2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001254 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1255 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001256
1257 controller.GoBack();
1258 EXPECT_EQ(0U, notifications.size());
1259
1260 // We should now have a pending navigation to go back.
1261 EXPECT_EQ(controller.GetEntryCount(), 2);
1262 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1263 EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
1264 EXPECT_TRUE(controller.GetLastCommittedEntry());
1265 EXPECT_TRUE(controller.GetPendingEntry());
1266 EXPECT_FALSE(controller.CanGoBack());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001267 EXPECT_FALSE(controller.CanGoToOffset(-1));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001268 EXPECT_TRUE(controller.CanGoForward());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001269 EXPECT_TRUE(controller.CanGoToOffset(1));
1270 EXPECT_FALSE(controller.CanGoToOffset(2)); // Cannot go foward 2 steps.
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001271
1272 // Timestamp for entry 1 should be on or after that of entry 0.
1273 EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null());
1274 EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(),
1275 controller.GetEntryAtIndex(0)->GetTimestamp());
1276
1277 test_rvh()->SendNavigate(0, url2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001278 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1279 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001280
1281 // The back navigation completed successfully.
1282 EXPECT_EQ(controller.GetEntryCount(), 2);
1283 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1284 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1285 EXPECT_TRUE(controller.GetLastCommittedEntry());
1286 EXPECT_FALSE(controller.GetPendingEntry());
1287 EXPECT_FALSE(controller.CanGoBack());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001288 EXPECT_FALSE(controller.CanGoToOffset(-1));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001289 EXPECT_TRUE(controller.CanGoForward());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001290 EXPECT_TRUE(controller.CanGoToOffset(1));
1291 EXPECT_FALSE(controller.CanGoToOffset(2)); // Cannot go foward 2 steps.
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001292
1293 // Timestamp for entry 0 should be on or after that of entry 1
1294 // (since we went back to it).
1295 EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(),
1296 controller.GetEntryAtIndex(1)->GetTimestamp());
1297}
1298
1299// Tests what happens when a back navigation produces a new page.
1300TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
1301 NavigationControllerImpl& controller = controller_impl();
1302 TestNotificationTracker notifications;
1303 RegisterForAllNavNotifications(&notifications, &controller);
1304
1305 const GURL url1("http://foo/1");
1306 const GURL url2("http://foo/2");
1307 const GURL url3("http://foo/3");
1308
1309 controller.LoadURL(
1310 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1311 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001312 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1313 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001314
1315 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1316 test_rvh()->SendNavigate(1, url2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001317 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1318 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001319
1320 controller.GoBack();
1321 EXPECT_EQ(0U, notifications.size());
1322
1323 // We should now have a pending navigation to go back.
1324 EXPECT_EQ(controller.GetEntryCount(), 2);
1325 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1326 EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
1327 EXPECT_TRUE(controller.GetLastCommittedEntry());
1328 EXPECT_TRUE(controller.GetPendingEntry());
1329 EXPECT_FALSE(controller.CanGoBack());
1330 EXPECT_TRUE(controller.CanGoForward());
1331
1332 test_rvh()->SendNavigate(2, url3);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001333 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1334 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001335
1336 // The back navigation resulted in a completely new navigation.
1337 // TODO(darin): perhaps this behavior will be confusing to users?
1338 EXPECT_EQ(controller.GetEntryCount(), 3);
1339 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
1340 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1341 EXPECT_TRUE(controller.GetLastCommittedEntry());
1342 EXPECT_FALSE(controller.GetPendingEntry());
1343 EXPECT_TRUE(controller.CanGoBack());
1344 EXPECT_FALSE(controller.CanGoForward());
1345}
1346
1347// Receives a back message when there is a new pending navigation entry.
1348TEST_F(NavigationControllerTest, Back_NewPending) {
1349 NavigationControllerImpl& controller = controller_impl();
1350 TestNotificationTracker notifications;
1351 RegisterForAllNavNotifications(&notifications, &controller);
1352
1353 const GURL kUrl1("http://foo1");
1354 const GURL kUrl2("http://foo2");
1355 const GURL kUrl3("http://foo3");
1356
1357 // First navigate two places so we have some back history.
1358 test_rvh()->SendNavigate(0, kUrl1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001359 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1360 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001361
1362 // controller.LoadURL(kUrl2, PAGE_TRANSITION_TYPED);
1363 test_rvh()->SendNavigate(1, kUrl2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001364 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1365 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001366
1367 // Now start a new pending navigation and go back before it commits.
1368 controller.LoadURL(kUrl3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1369 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1370 EXPECT_EQ(kUrl3, controller.GetPendingEntry()->GetURL());
1371 controller.GoBack();
1372
1373 // The pending navigation should now be the "back" item and the new one
1374 // should be gone.
1375 EXPECT_EQ(0, controller.GetPendingEntryIndex());
1376 EXPECT_EQ(kUrl1, controller.GetPendingEntry()->GetURL());
1377}
1378
1379// Receives a back message when there is a different renavigation already
1380// pending.
1381TEST_F(NavigationControllerTest, Back_OtherBackPending) {
1382 NavigationControllerImpl& controller = controller_impl();
1383 const GURL kUrl1("http://foo/1");
1384 const GURL kUrl2("http://foo/2");
1385 const GURL kUrl3("http://foo/3");
1386
1387 // First navigate three places so we have some back history.
1388 test_rvh()->SendNavigate(0, kUrl1);
1389 test_rvh()->SendNavigate(1, kUrl2);
1390 test_rvh()->SendNavigate(2, kUrl3);
1391
1392 // With nothing pending, say we get a navigation to the second entry.
1393 test_rvh()->SendNavigate(1, kUrl2);
1394
1395 // We know all the entries have the same site instance, so we can just grab
1396 // a random one for looking up other entries.
1397 SiteInstance* site_instance =
1398 NavigationEntryImpl::FromNavigationEntry(
1399 controller.GetLastCommittedEntry())->site_instance();
1400
1401 // That second URL should be the last committed and it should have gotten the
1402 // new title.
1403 EXPECT_EQ(kUrl2, controller.GetEntryWithPageID(site_instance, 1)->GetURL());
1404 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
1405 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1406
1407 // Now go forward to the last item again and say it was committed.
1408 controller.GoForward();
1409 test_rvh()->SendNavigate(2, kUrl3);
1410
1411 // Now start going back one to the second page. It will be pending.
1412 controller.GoBack();
1413 EXPECT_EQ(1, controller.GetPendingEntryIndex());
1414 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
1415
1416 // Not synthesize a totally new back event to the first page. This will not
1417 // match the pending one.
1418 test_rvh()->SendNavigate(0, kUrl1);
1419
1420 // The committed navigation should clear the pending entry.
1421 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1422
1423 // But the navigated entry should be the last committed.
1424 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
1425 EXPECT_EQ(kUrl1, controller.GetLastCommittedEntry()->GetURL());
1426}
1427
1428// Tests what happens when we navigate forward successfully.
1429TEST_F(NavigationControllerTest, Forward) {
1430 NavigationControllerImpl& controller = controller_impl();
1431 TestNotificationTracker notifications;
1432 RegisterForAllNavNotifications(&notifications, &controller);
1433
1434 const GURL url1("http://foo1");
1435 const GURL url2("http://foo2");
1436
1437 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001438 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1439 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001440
1441 test_rvh()->SendNavigate(1, url2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001442 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1443 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001444
1445 controller.GoBack();
1446 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001447 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1448 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001449
1450 controller.GoForward();
1451
1452 // We should now have a pending navigation to go forward.
1453 EXPECT_EQ(controller.GetEntryCount(), 2);
1454 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1455 EXPECT_EQ(controller.GetPendingEntryIndex(), 1);
1456 EXPECT_TRUE(controller.GetLastCommittedEntry());
1457 EXPECT_TRUE(controller.GetPendingEntry());
1458 EXPECT_TRUE(controller.CanGoBack());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001459 EXPECT_TRUE(controller.CanGoToOffset(-1));
1460 EXPECT_FALSE(controller.CanGoToOffset(-2)); // Cannot go back 2 steps.
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001461 EXPECT_FALSE(controller.CanGoForward());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001462 EXPECT_FALSE(controller.CanGoToOffset(1));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001463
1464 // Timestamp for entry 0 should be on or after that of entry 1
1465 // (since we went back to it).
1466 EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null());
1467 EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(),
1468 controller.GetEntryAtIndex(1)->GetTimestamp());
1469
1470 test_rvh()->SendNavigate(1, url2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001471 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1472 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001473
1474 // The forward navigation completed successfully.
1475 EXPECT_EQ(controller.GetEntryCount(), 2);
1476 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1477 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1478 EXPECT_TRUE(controller.GetLastCommittedEntry());
1479 EXPECT_FALSE(controller.GetPendingEntry());
1480 EXPECT_TRUE(controller.CanGoBack());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001481 EXPECT_TRUE(controller.CanGoToOffset(-1));
1482 EXPECT_FALSE(controller.CanGoToOffset(-2)); // Cannot go back 2 steps.
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001483 EXPECT_FALSE(controller.CanGoForward());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001484 EXPECT_FALSE(controller.CanGoToOffset(1));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001485
1486 // Timestamp for entry 1 should be on or after that of entry 0
1487 // (since we went forward to it).
1488 EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(),
1489 controller.GetEntryAtIndex(0)->GetTimestamp());
1490}
1491
1492// Tests what happens when a forward navigation produces a new page.
1493TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
1494 NavigationControllerImpl& controller = controller_impl();
1495 TestNotificationTracker notifications;
1496 RegisterForAllNavNotifications(&notifications, &controller);
1497
1498 const GURL url1("http://foo1");
1499 const GURL url2("http://foo2");
1500 const GURL url3("http://foo3");
1501
1502 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001503 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1504 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001505 test_rvh()->SendNavigate(1, url2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001506 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1507 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001508
1509 controller.GoBack();
1510 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001511 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1512 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001513
1514 controller.GoForward();
1515 EXPECT_EQ(0U, notifications.size());
1516
1517 // Should now have a pending navigation to go forward.
1518 EXPECT_EQ(controller.GetEntryCount(), 2);
1519 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1520 EXPECT_EQ(controller.GetPendingEntryIndex(), 1);
1521 EXPECT_TRUE(controller.GetLastCommittedEntry());
1522 EXPECT_TRUE(controller.GetPendingEntry());
1523 EXPECT_TRUE(controller.CanGoBack());
1524 EXPECT_FALSE(controller.CanGoForward());
1525
1526 test_rvh()->SendNavigate(2, url3);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001527 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1528 navigation_entry_committed_counter_ = 0;
1529 EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_LIST_PRUNED));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001530
1531 EXPECT_EQ(controller.GetEntryCount(), 2);
1532 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1533 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1534 EXPECT_TRUE(controller.GetLastCommittedEntry());
1535 EXPECT_FALSE(controller.GetPendingEntry());
1536 EXPECT_TRUE(controller.CanGoBack());
1537 EXPECT_FALSE(controller.CanGoForward());
1538}
1539
1540// Two consequent navigation for the same URL entered in should be considered
1541// as SAME_PAGE navigation even when we are redirected to some other page.
1542TEST_F(NavigationControllerTest, Redirect) {
1543 NavigationControllerImpl& controller = controller_impl();
1544 TestNotificationTracker notifications;
1545 RegisterForAllNavNotifications(&notifications, &controller);
1546
1547 const GURL url1("http://foo1");
1548 const GURL url2("http://foo2"); // Redirection target
1549
1550 // First request
1551 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1552
1553 EXPECT_EQ(0U, notifications.size());
1554 test_rvh()->SendNavigate(0, url2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001555 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1556 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001557
1558 // Second request
1559 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1560
1561 EXPECT_TRUE(controller.GetPendingEntry());
1562 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1563 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
1564
1565 ViewHostMsg_FrameNavigate_Params params;
1566 params.page_id = 0;
1567 params.url = url2;
1568 params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
1569 params.redirects.push_back(GURL("http://foo1"));
1570 params.redirects.push_back(GURL("http://foo2"));
1571 params.should_update_history = false;
1572 params.gesture = NavigationGestureAuto;
1573 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001574 params.page_state = PageState::CreateFromURL(url2);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001575
1576 LoadCommittedDetails details;
1577
1578 EXPECT_EQ(0U, notifications.size());
1579 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001580 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1581 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001582
1583 EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE);
1584 EXPECT_EQ(controller.GetEntryCount(), 1);
1585 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1586 EXPECT_TRUE(controller.GetLastCommittedEntry());
1587 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1588 EXPECT_FALSE(controller.GetPendingEntry());
1589 EXPECT_EQ(url2, controller.GetActiveEntry()->GetURL());
1590
1591 EXPECT_FALSE(controller.CanGoBack());
1592 EXPECT_FALSE(controller.CanGoForward());
1593}
1594
1595// Similar to Redirect above, but the first URL is requested by POST,
1596// the second URL is requested by GET. NavigationEntry::has_post_data_
1597// must be cleared. http://crbug.com/21245
1598TEST_F(NavigationControllerTest, PostThenRedirect) {
1599 NavigationControllerImpl& controller = controller_impl();
1600 TestNotificationTracker notifications;
1601 RegisterForAllNavNotifications(&notifications, &controller);
1602
1603 const GURL url1("http://foo1");
1604 const GURL url2("http://foo2"); // Redirection target
1605
1606 // First request as POST
1607 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1608 controller.GetActiveEntry()->SetHasPostData(true);
1609
1610 EXPECT_EQ(0U, notifications.size());
1611 test_rvh()->SendNavigate(0, url2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001612 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1613 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001614
1615 // Second request
1616 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1617
1618 EXPECT_TRUE(controller.GetPendingEntry());
1619 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1620 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
1621
1622 ViewHostMsg_FrameNavigate_Params params;
1623 params.page_id = 0;
1624 params.url = url2;
1625 params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
1626 params.redirects.push_back(GURL("http://foo1"));
1627 params.redirects.push_back(GURL("http://foo2"));
1628 params.should_update_history = false;
1629 params.gesture = NavigationGestureAuto;
1630 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001631 params.page_state = PageState::CreateFromURL(url2);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001632
1633 LoadCommittedDetails details;
1634
1635 EXPECT_EQ(0U, notifications.size());
1636 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001637 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1638 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001639
1640 EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE);
1641 EXPECT_EQ(controller.GetEntryCount(), 1);
1642 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1643 EXPECT_TRUE(controller.GetLastCommittedEntry());
1644 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1645 EXPECT_FALSE(controller.GetPendingEntry());
1646 EXPECT_EQ(url2, controller.GetActiveEntry()->GetURL());
1647 EXPECT_FALSE(controller.GetActiveEntry()->GetHasPostData());
1648
1649 EXPECT_FALSE(controller.CanGoBack());
1650 EXPECT_FALSE(controller.CanGoForward());
1651}
1652
1653// A redirect right off the bat should be a NEW_PAGE.
1654TEST_F(NavigationControllerTest, ImmediateRedirect) {
1655 NavigationControllerImpl& controller = controller_impl();
1656 TestNotificationTracker notifications;
1657 RegisterForAllNavNotifications(&notifications, &controller);
1658
1659 const GURL url1("http://foo1");
1660 const GURL url2("http://foo2"); // Redirection target
1661
1662 // First request
1663 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1664
1665 EXPECT_TRUE(controller.GetPendingEntry());
1666 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1667 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
1668
1669 ViewHostMsg_FrameNavigate_Params params;
1670 params.page_id = 0;
1671 params.url = url2;
1672 params.transition = PAGE_TRANSITION_SERVER_REDIRECT;
1673 params.redirects.push_back(GURL("http://foo1"));
1674 params.redirects.push_back(GURL("http://foo2"));
1675 params.should_update_history = false;
1676 params.gesture = NavigationGestureAuto;
1677 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001678 params.page_state = PageState::CreateFromURL(url2);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001679
1680 LoadCommittedDetails details;
1681
1682 EXPECT_EQ(0U, notifications.size());
1683 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001684 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1685 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001686
1687 EXPECT_TRUE(details.type == NAVIGATION_TYPE_NEW_PAGE);
1688 EXPECT_EQ(controller.GetEntryCount(), 1);
1689 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1690 EXPECT_TRUE(controller.GetLastCommittedEntry());
1691 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1692 EXPECT_FALSE(controller.GetPendingEntry());
1693 EXPECT_EQ(url2, controller.GetActiveEntry()->GetURL());
1694
1695 EXPECT_FALSE(controller.CanGoBack());
1696 EXPECT_FALSE(controller.CanGoForward());
1697}
1698
1699// Tests navigation via link click within a subframe. A new navigation entry
1700// should be created.
1701TEST_F(NavigationControllerTest, NewSubframe) {
1702 NavigationControllerImpl& controller = controller_impl();
1703 TestNotificationTracker notifications;
1704 RegisterForAllNavNotifications(&notifications, &controller);
1705
1706 const GURL url1("http://foo1");
1707 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001708 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1709 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001710
1711 const GURL url2("http://foo2");
1712 ViewHostMsg_FrameNavigate_Params params;
1713 params.page_id = 1;
1714 params.url = url2;
1715 params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
1716 params.should_update_history = false;
1717 params.gesture = NavigationGestureUser;
1718 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001719 params.page_state = PageState::CreateFromURL(url2);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001720
1721 LoadCommittedDetails details;
1722 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001723 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1724 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001725 EXPECT_EQ(url1, details.previous_url);
1726 EXPECT_FALSE(details.is_in_page);
1727 EXPECT_FALSE(details.is_main_frame);
1728
1729 // The new entry should be appended.
1730 EXPECT_EQ(2, controller.GetEntryCount());
1731
1732 // New entry should refer to the new page, but the old URL (entries only
1733 // reflect the toplevel URL).
1734 EXPECT_EQ(url1, details.entry->GetURL());
1735 EXPECT_EQ(params.page_id, details.entry->GetPageID());
1736}
1737
1738// Some pages create a popup, then write an iframe into it. This causes a
1739// subframe navigation without having any committed entry. Such navigations
1740// just get thrown on the ground, but we shouldn't crash.
1741TEST_F(NavigationControllerTest, SubframeOnEmptyPage) {
1742 NavigationControllerImpl& controller = controller_impl();
1743 TestNotificationTracker notifications;
1744 RegisterForAllNavNotifications(&notifications, &controller);
1745
1746 // Navigation controller currently has no entries.
1747 const GURL url("http://foo2");
1748 ViewHostMsg_FrameNavigate_Params params;
1749 params.page_id = 1;
1750 params.url = url;
1751 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
1752 params.should_update_history = false;
1753 params.gesture = NavigationGestureAuto;
1754 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001755 params.page_state = PageState::CreateFromURL(url);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001756
1757 LoadCommittedDetails details;
1758 EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
1759 EXPECT_EQ(0U, notifications.size());
1760}
1761
1762// Auto subframes are ones the page loads automatically like ads. They should
1763// not create new navigation entries.
1764TEST_F(NavigationControllerTest, AutoSubframe) {
1765 NavigationControllerImpl& controller = controller_impl();
1766 TestNotificationTracker notifications;
1767 RegisterForAllNavNotifications(&notifications, &controller);
1768
1769 const GURL url1("http://foo1");
1770 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001771 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1772 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001773
1774 const GURL url2("http://foo2");
1775 ViewHostMsg_FrameNavigate_Params params;
1776 params.page_id = 0;
1777 params.url = url2;
1778 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
1779 params.should_update_history = false;
1780 params.gesture = NavigationGestureUser;
1781 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001782 params.page_state = PageState::CreateFromURL(url2);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001783
1784 // Navigating should do nothing.
1785 LoadCommittedDetails details;
1786 EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
1787 EXPECT_EQ(0U, notifications.size());
1788
1789 // There should still be only one entry.
1790 EXPECT_EQ(1, controller.GetEntryCount());
1791}
1792
1793// Tests navigation and then going back to a subframe navigation.
1794TEST_F(NavigationControllerTest, BackSubframe) {
1795 NavigationControllerImpl& controller = controller_impl();
1796 TestNotificationTracker notifications;
1797 RegisterForAllNavNotifications(&notifications, &controller);
1798
1799 // Main page.
1800 const GURL url1("http://foo1");
1801 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001802 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1803 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001804
1805 // First manual subframe navigation.
1806 const GURL url2("http://foo2");
1807 ViewHostMsg_FrameNavigate_Params params;
1808 params.page_id = 1;
1809 params.url = url2;
1810 params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
1811 params.should_update_history = false;
1812 params.gesture = NavigationGestureUser;
1813 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001814 params.page_state = PageState::CreateFromURL(url2);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001815
1816 // This should generate a new entry.
1817 LoadCommittedDetails details;
1818 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001819 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1820 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001821 EXPECT_EQ(2, controller.GetEntryCount());
1822
1823 // Second manual subframe navigation should also make a new entry.
1824 const GURL url3("http://foo3");
1825 params.page_id = 2;
1826 params.url = url3;
1827 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001828 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1829 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001830 EXPECT_EQ(3, controller.GetEntryCount());
1831 EXPECT_EQ(2, controller.GetCurrentEntryIndex());
1832
1833 // Go back one.
1834 controller.GoBack();
1835 params.url = url2;
1836 params.page_id = 1;
1837 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001838 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1839 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001840 EXPECT_EQ(3, controller.GetEntryCount());
1841 EXPECT_EQ(1, controller.GetCurrentEntryIndex());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001842 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1843 EXPECT_FALSE(controller.GetPendingEntry());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001844
1845 // Go back one more.
1846 controller.GoBack();
1847 params.url = url1;
1848 params.page_id = 0;
1849 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001850 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1851 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001852 EXPECT_EQ(3, controller.GetEntryCount());
1853 EXPECT_EQ(0, controller.GetCurrentEntryIndex());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001854 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
1855 EXPECT_FALSE(controller.GetPendingEntry());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001856}
1857
1858TEST_F(NavigationControllerTest, LinkClick) {
1859 NavigationControllerImpl& controller = controller_impl();
1860 TestNotificationTracker notifications;
1861 RegisterForAllNavNotifications(&notifications, &controller);
1862
1863 const GURL url1("http://foo1");
1864 const GURL url2("http://foo2");
1865
1866 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001867 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1868 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001869
1870 test_rvh()->SendNavigate(1, url2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001871 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1872 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001873
1874 // Should not have produced a new session history entry.
1875 EXPECT_EQ(controller.GetEntryCount(), 2);
1876 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1877 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1878 EXPECT_TRUE(controller.GetLastCommittedEntry());
1879 EXPECT_FALSE(controller.GetPendingEntry());
1880 EXPECT_TRUE(controller.CanGoBack());
1881 EXPECT_FALSE(controller.CanGoForward());
1882}
1883
1884TEST_F(NavigationControllerTest, InPage) {
1885 NavigationControllerImpl& controller = controller_impl();
1886 TestNotificationTracker notifications;
1887 RegisterForAllNavNotifications(&notifications, &controller);
1888
1889 // Main page.
1890 const GURL url1("http://foo");
1891 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001892 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1893 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001894
1895 // Ensure main page navigation to same url respects the was_within_same_page
1896 // hint provided in the params.
1897 ViewHostMsg_FrameNavigate_Params self_params;
1898 self_params.page_id = 0;
1899 self_params.url = url1;
1900 self_params.transition = PAGE_TRANSITION_LINK;
1901 self_params.should_update_history = false;
1902 self_params.gesture = NavigationGestureUser;
1903 self_params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001904 self_params.page_state = PageState::CreateFromURL(url1);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001905 self_params.was_within_same_page = true;
1906
1907 LoadCommittedDetails details;
1908 EXPECT_TRUE(controller.RendererDidNavigate(self_params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001909 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1910 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001911 EXPECT_TRUE(details.is_in_page);
1912 EXPECT_TRUE(details.did_replace_entry);
1913 EXPECT_EQ(1, controller.GetEntryCount());
1914
1915 // Fragment navigation to a new page_id.
1916 const GURL url2("http://foo#a");
1917 ViewHostMsg_FrameNavigate_Params params;
1918 params.page_id = 1;
1919 params.url = url2;
1920 params.transition = PAGE_TRANSITION_LINK;
1921 params.should_update_history = false;
1922 params.gesture = NavigationGestureUser;
1923 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01001924 params.page_state = PageState::CreateFromURL(url2);
Ben Murdochbb1529c2013-08-08 10:24:53 +01001925 params.was_within_same_page = true;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001926
1927 // This should generate a new entry.
1928 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001929 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1930 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001931 EXPECT_TRUE(details.is_in_page);
1932 EXPECT_FALSE(details.did_replace_entry);
1933 EXPECT_EQ(2, controller.GetEntryCount());
1934
1935 // Go back one.
1936 ViewHostMsg_FrameNavigate_Params back_params(params);
1937 controller.GoBack();
1938 back_params.url = url1;
1939 back_params.page_id = 0;
1940 EXPECT_TRUE(controller.RendererDidNavigate(back_params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001941 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1942 navigation_entry_committed_counter_ = 0;
Ben Murdochbb1529c2013-08-08 10:24:53 +01001943 EXPECT_TRUE(details.is_in_page);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001944 EXPECT_EQ(2, controller.GetEntryCount());
1945 EXPECT_EQ(0, controller.GetCurrentEntryIndex());
1946 EXPECT_EQ(back_params.url, controller.GetActiveEntry()->GetURL());
1947
1948 // Go forward
1949 ViewHostMsg_FrameNavigate_Params forward_params(params);
1950 controller.GoForward();
1951 forward_params.url = url2;
1952 forward_params.page_id = 1;
1953 EXPECT_TRUE(controller.RendererDidNavigate(forward_params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001954 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1955 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001956 EXPECT_TRUE(details.is_in_page);
1957 EXPECT_EQ(2, controller.GetEntryCount());
1958 EXPECT_EQ(1, controller.GetCurrentEntryIndex());
1959 EXPECT_EQ(forward_params.url,
1960 controller.GetActiveEntry()->GetURL());
1961
1962 // Now go back and forward again. This is to work around a bug where we would
1963 // compare the incoming URL with the last committed entry rather than the
1964 // one identified by an existing page ID. This would result in the second URL
1965 // losing the reference fragment when you navigate away from it and then back.
1966 controller.GoBack();
1967 EXPECT_TRUE(controller.RendererDidNavigate(back_params, &details));
1968 controller.GoForward();
1969 EXPECT_TRUE(controller.RendererDidNavigate(forward_params, &details));
1970 EXPECT_EQ(forward_params.url,
1971 controller.GetActiveEntry()->GetURL());
1972
1973 // Finally, navigate to an unrelated URL to make sure in_page is not sticky.
1974 const GURL url3("http://bar");
1975 params.page_id = 2;
1976 params.url = url3;
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001977 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001978 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001979 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1980 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001981 EXPECT_FALSE(details.is_in_page);
1982 EXPECT_EQ(3, controller.GetEntryCount());
1983 EXPECT_EQ(2, controller.GetCurrentEntryIndex());
1984}
1985
1986TEST_F(NavigationControllerTest, InPage_Replace) {
1987 NavigationControllerImpl& controller = controller_impl();
1988 TestNotificationTracker notifications;
1989 RegisterForAllNavNotifications(&notifications, &controller);
1990
1991 // Main page.
1992 const GURL url1("http://foo");
1993 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01001994 EXPECT_EQ(1U, navigation_entry_committed_counter_);
1995 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001996
1997 // First navigation.
1998 const GURL url2("http://foo#a");
1999 ViewHostMsg_FrameNavigate_Params params;
2000 params.page_id = 0; // Same page_id
2001 params.url = url2;
2002 params.transition = PAGE_TRANSITION_LINK;
2003 params.should_update_history = false;
2004 params.gesture = NavigationGestureUser;
2005 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002006 params.page_state = PageState::CreateFromURL(url2);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002007
2008 // This should NOT generate a new entry, nor prune the list.
2009 LoadCommittedDetails details;
2010 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01002011 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2012 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002013 EXPECT_TRUE(details.is_in_page);
2014 EXPECT_TRUE(details.did_replace_entry);
2015 EXPECT_EQ(1, controller.GetEntryCount());
2016}
2017
2018// Tests for http://crbug.com/40395
2019// Simulates this:
2020// <script>
2021// window.location.replace("#a");
2022// window.location='http://foo3/';
2023// </script>
2024TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
2025 NavigationControllerImpl& controller = controller_impl();
2026 TestNotificationTracker notifications;
2027 RegisterForAllNavNotifications(&notifications, &controller);
2028
2029 // Load an initial page.
2030 {
2031 const GURL url("http://foo/");
2032 test_rvh()->SendNavigate(0, url);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01002033 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2034 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002035 }
2036
2037 // Navigate to a new page.
2038 {
2039 const GURL url("http://foo2/");
2040 test_rvh()->SendNavigate(1, url);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01002041 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2042 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002043 }
2044
2045 // Navigate within the page.
2046 {
2047 const GURL url("http://foo2/#a");
2048 ViewHostMsg_FrameNavigate_Params params;
2049 params.page_id = 1; // Same page_id
2050 params.url = url;
2051 params.transition = PAGE_TRANSITION_LINK;
2052 params.redirects.push_back(url);
2053 params.should_update_history = true;
2054 params.gesture = NavigationGestureUnknown;
2055 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002056 params.page_state = PageState::CreateFromURL(url);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002057
2058 // This should NOT generate a new entry, nor prune the list.
2059 LoadCommittedDetails details;
2060 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01002061 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2062 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002063 EXPECT_TRUE(details.is_in_page);
2064 EXPECT_TRUE(details.did_replace_entry);
2065 EXPECT_EQ(2, controller.GetEntryCount());
2066 }
2067
2068 // Perform a client redirect to a new page.
2069 {
2070 const GURL url("http://foo3/");
2071 ViewHostMsg_FrameNavigate_Params params;
2072 params.page_id = 2; // New page_id
2073 params.url = url;
2074 params.transition = PAGE_TRANSITION_CLIENT_REDIRECT;
2075 params.redirects.push_back(GURL("http://foo2/#a"));
2076 params.redirects.push_back(url);
2077 params.should_update_history = true;
2078 params.gesture = NavigationGestureUnknown;
2079 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002080 params.page_state = PageState::CreateFromURL(url);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002081
2082 // This SHOULD generate a new entry.
2083 LoadCommittedDetails details;
2084 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01002085 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2086 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002087 EXPECT_FALSE(details.is_in_page);
2088 EXPECT_EQ(3, controller.GetEntryCount());
2089 }
2090
2091 // Verify that BACK brings us back to http://foo2/.
2092 {
2093 const GURL url("http://foo2/");
2094 controller.GoBack();
2095 test_rvh()->SendNavigate(1, url);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01002096 EXPECT_EQ(1U, navigation_entry_committed_counter_);
2097 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002098 EXPECT_EQ(url, controller.GetActiveEntry()->GetURL());
2099 }
2100}
2101
2102// NotificationObserver implementation used in verifying we've received the
2103// NOTIFICATION_NAV_LIST_PRUNED method.
2104class PrunedListener : public NotificationObserver {
2105 public:
2106 explicit PrunedListener(NavigationControllerImpl* controller)
2107 : notification_count_(0) {
2108 registrar_.Add(this, NOTIFICATION_NAV_LIST_PRUNED,
2109 Source<NavigationController>(controller));
2110 }
2111
2112 virtual void Observe(int type,
2113 const NotificationSource& source,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002114 const NotificationDetails& details) OVERRIDE {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002115 if (type == NOTIFICATION_NAV_LIST_PRUNED) {
2116 notification_count_++;
2117 details_ = *(Details<PrunedDetails>(details).ptr());
2118 }
2119 }
2120
2121 // Number of times NAV_LIST_PRUNED has been observed.
2122 int notification_count_;
2123
2124 // Details from the last NAV_LIST_PRUNED.
2125 PrunedDetails details_;
2126
2127 private:
2128 NotificationRegistrar registrar_;
2129
2130 DISALLOW_COPY_AND_ASSIGN(PrunedListener);
2131};
2132
2133// Tests that we limit the number of navigation entries created correctly.
2134TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
2135 NavigationControllerImpl& controller = controller_impl();
2136 size_t original_count = NavigationControllerImpl::max_entry_count();
2137 const int kMaxEntryCount = 5;
2138
2139 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
2140
2141 int url_index;
2142 // Load up to the max count, all entries should be there.
2143 for (url_index = 0; url_index < kMaxEntryCount; url_index++) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002144 GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002145 controller.LoadURL(
2146 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2147 test_rvh()->SendNavigate(url_index, url);
2148 }
2149
2150 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
2151
2152 // Created a PrunedListener to observe prune notifications.
2153 PrunedListener listener(&controller);
2154
2155 // Navigate some more.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002156 GURL url(base::StringPrintf("http://www.a.com/%d", url_index));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002157 controller.LoadURL(
2158 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2159 test_rvh()->SendNavigate(url_index, url);
2160 url_index++;
2161
2162 // We should have got a pruned navigation.
2163 EXPECT_EQ(1, listener.notification_count_);
2164 EXPECT_TRUE(listener.details_.from_front);
2165 EXPECT_EQ(1, listener.details_.count);
2166
2167 // We expect http://www.a.com/0 to be gone.
2168 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
2169 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
2170 GURL("http:////www.a.com/1"));
2171
2172 // More navigations.
2173 for (int i = 0; i < 3; i++) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002174 url = GURL(base::StringPrintf("http:////www.a.com/%d", url_index));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002175 controller.LoadURL(
2176 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2177 test_rvh()->SendNavigate(url_index, url);
2178 url_index++;
2179 }
2180 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
2181 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
2182 GURL("http:////www.a.com/4"));
2183
2184 NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
2185}
2186
2187// Tests that we can do a restore and navigate to the restored entries and
2188// everything is updated properly. This can be tricky since there is no
2189// SiteInstance for the entries created initially.
2190TEST_F(NavigationControllerTest, RestoreNavigate) {
2191 // Create a NavigationController with a restored set of tabs.
2192 GURL url("http://foo");
2193 std::vector<NavigationEntry*> entries;
2194 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
2195 url, Referrer(), PAGE_TRANSITION_RELOAD, false, std::string(),
2196 browser_context());
2197 entry->SetPageID(0);
2198 entry->SetTitle(ASCIIToUTF16("Title"));
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002199 entry->SetPageState(PageState::CreateFromEncodedData("state"));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002200 const base::Time timestamp = base::Time::Now();
2201 entry->SetTimestamp(timestamp);
2202 entries.push_back(entry);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002203 scoped_ptr<WebContentsImpl> our_contents(static_cast<WebContentsImpl*>(
2204 WebContents::Create(WebContents::CreateParams(browser_context()))));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002205 NavigationControllerImpl& our_controller = our_contents->GetController();
2206 our_controller.Restore(
2207 0,
2208 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
2209 &entries);
2210 ASSERT_EQ(0u, entries.size());
2211
2212 // Before navigating to the restored entry, it should have a restore_type
2213 // and no SiteInstance.
2214 ASSERT_EQ(1, our_controller.GetEntryCount());
2215 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
2216 NavigationEntryImpl::FromNavigationEntry(
2217 our_controller.GetEntryAtIndex(0))->restore_type());
2218 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
2219 our_controller.GetEntryAtIndex(0))->site_instance());
2220
2221 // After navigating, we should have one entry, and it should be "pending".
2222 // It should now have a SiteInstance and no restore_type.
2223 our_controller.GoToIndex(0);
2224 EXPECT_EQ(1, our_controller.GetEntryCount());
2225 EXPECT_EQ(our_controller.GetEntryAtIndex(0),
2226 our_controller.GetPendingEntry());
2227 EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
2228 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
2229 NavigationEntryImpl::FromNavigationEntry
2230 (our_controller.GetEntryAtIndex(0))->restore_type());
2231 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
2232 our_controller.GetEntryAtIndex(0))->site_instance());
2233
2234 // Timestamp should remain the same before the navigation finishes.
2235 EXPECT_EQ(timestamp, our_controller.GetEntryAtIndex(0)->GetTimestamp());
2236
2237 // Say we navigated to that entry.
2238 ViewHostMsg_FrameNavigate_Params params;
2239 params.page_id = 0;
2240 params.url = url;
2241 params.transition = PAGE_TRANSITION_LINK;
2242 params.should_update_history = false;
2243 params.gesture = NavigationGestureUser;
2244 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002245 params.page_state = PageState::CreateFromURL(url);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002246 LoadCommittedDetails details;
2247 our_controller.RendererDidNavigate(params, &details);
2248
2249 // There should be no longer any pending entry and one committed one. This
2250 // means that we were able to locate the entry, assign its site instance, and
2251 // commit it properly.
2252 EXPECT_EQ(1, our_controller.GetEntryCount());
2253 EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
2254 EXPECT_FALSE(our_controller.GetPendingEntry());
2255 EXPECT_EQ(url,
2256 NavigationEntryImpl::FromNavigationEntry(
2257 our_controller.GetLastCommittedEntry())->site_instance()->
2258 GetSiteURL());
2259 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
2260 NavigationEntryImpl::FromNavigationEntry(
2261 our_controller.GetEntryAtIndex(0))->restore_type());
2262
2263 // Timestamp should have been updated.
2264 EXPECT_GE(our_controller.GetEntryAtIndex(0)->GetTimestamp(), timestamp);
2265}
2266
2267// Tests that we can still navigate to a restored entry after a different
2268// navigation fails and clears the pending entry. http://crbug.com/90085
2269TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
2270 // Create a NavigationController with a restored set of tabs.
2271 GURL url("http://foo");
2272 std::vector<NavigationEntry*> entries;
2273 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
2274 url, Referrer(), PAGE_TRANSITION_RELOAD, false, std::string(),
2275 browser_context());
2276 entry->SetPageID(0);
2277 entry->SetTitle(ASCIIToUTF16("Title"));
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002278 entry->SetPageState(PageState::CreateFromEncodedData("state"));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002279 entries.push_back(entry);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002280 scoped_ptr<WebContentsImpl> our_contents(static_cast<WebContentsImpl*>(
2281 WebContents::Create(WebContents::CreateParams(browser_context()))));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002282 NavigationControllerImpl& our_controller = our_contents->GetController();
2283 our_controller.Restore(
2284 0, NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY, &entries);
2285 ASSERT_EQ(0u, entries.size());
2286
2287 // Before navigating to the restored entry, it should have a restore_type
2288 // and no SiteInstance.
2289 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY,
2290 NavigationEntryImpl::FromNavigationEntry(
2291 our_controller.GetEntryAtIndex(0))->restore_type());
2292 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
2293 our_controller.GetEntryAtIndex(0))->site_instance());
2294
2295 // After navigating, we should have one entry, and it should be "pending".
2296 // It should now have a SiteInstance and no restore_type.
2297 our_controller.GoToIndex(0);
2298 EXPECT_EQ(1, our_controller.GetEntryCount());
2299 EXPECT_EQ(our_controller.GetEntryAtIndex(0),
2300 our_controller.GetPendingEntry());
2301 EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
2302 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
2303 NavigationEntryImpl::FromNavigationEntry(
2304 our_controller.GetEntryAtIndex(0))->restore_type());
2305 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
2306 our_controller.GetEntryAtIndex(0))->site_instance());
2307
2308 // This pending navigation may have caused a different navigation to fail,
2309 // which causes the pending entry to be cleared.
2310 TestRenderViewHost* rvh =
2311 static_cast<TestRenderViewHost*>(our_contents->GetRenderViewHost());
2312 ViewHostMsg_DidFailProvisionalLoadWithError_Params fail_load_params;
2313 fail_load_params.frame_id = 1;
2314 fail_load_params.is_main_frame = true;
2315 fail_load_params.error_code = net::ERR_ABORTED;
2316 fail_load_params.error_description = string16();
2317 fail_load_params.url = url;
2318 fail_load_params.showing_repost_interstitial = false;
2319 rvh->OnMessageReceived(
2320 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
2321 fail_load_params));
2322
2323 // Now the pending restored entry commits.
2324 ViewHostMsg_FrameNavigate_Params params;
2325 params.page_id = 0;
2326 params.url = url;
2327 params.transition = PAGE_TRANSITION_LINK;
2328 params.should_update_history = false;
2329 params.gesture = NavigationGestureUser;
2330 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002331 params.page_state = PageState::CreateFromURL(url);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002332 LoadCommittedDetails details;
2333 our_controller.RendererDidNavigate(params, &details);
2334
2335 // There should be no pending entry and one committed one.
2336 EXPECT_EQ(1, our_controller.GetEntryCount());
2337 EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
2338 EXPECT_FALSE(our_controller.GetPendingEntry());
2339 EXPECT_EQ(url,
2340 NavigationEntryImpl::FromNavigationEntry(
2341 our_controller.GetLastCommittedEntry())->site_instance()->
2342 GetSiteURL());
2343 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
2344 NavigationEntryImpl::FromNavigationEntry(
2345 our_controller.GetEntryAtIndex(0))->restore_type());
2346}
2347
2348// Make sure that the page type and stuff is correct after an interstitial.
2349TEST_F(NavigationControllerTest, Interstitial) {
2350 NavigationControllerImpl& controller = controller_impl();
2351 // First navigate somewhere normal.
2352 const GURL url1("http://foo");
2353 controller.LoadURL(
2354 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2355 test_rvh()->SendNavigate(0, url1);
2356
2357 // Now navigate somewhere with an interstitial.
2358 const GURL url2("http://bar");
2359 controller.LoadURL(
2360 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2361 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
2362 set_page_type(PAGE_TYPE_INTERSTITIAL);
2363
2364 // At this point the interstitial will be displayed and the load will still
2365 // be pending. If the user continues, the load will commit.
2366 test_rvh()->SendNavigate(1, url2);
2367
2368 // The page should be a normal page again.
2369 EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
2370 EXPECT_EQ(PAGE_TYPE_NORMAL,
2371 controller.GetLastCommittedEntry()->GetPageType());
2372}
2373
2374TEST_F(NavigationControllerTest, RemoveEntry) {
2375 NavigationControllerImpl& controller = controller_impl();
2376 const GURL url1("http://foo/1");
2377 const GURL url2("http://foo/2");
2378 const GURL url3("http://foo/3");
2379 const GURL url4("http://foo/4");
2380 const GURL url5("http://foo/5");
2381 const GURL pending_url("http://foo/pending");
2382 const GURL default_url("http://foo/default");
2383
2384 controller.LoadURL(
2385 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2386 test_rvh()->SendNavigate(0, url1);
2387 controller.LoadURL(
2388 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2389 test_rvh()->SendNavigate(1, url2);
2390 controller.LoadURL(
2391 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2392 test_rvh()->SendNavigate(2, url3);
2393 controller.LoadURL(
2394 url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2395 test_rvh()->SendNavigate(3, url4);
2396 controller.LoadURL(
2397 url5, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2398 test_rvh()->SendNavigate(4, url5);
2399
2400 // Try to remove the last entry. Will fail because it is the current entry.
Ben Murdocha3f7b4e2013-07-24 10:36:34 +01002401 EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002402 EXPECT_EQ(5, controller.GetEntryCount());
2403 EXPECT_EQ(4, controller.GetLastCommittedEntryIndex());
2404
Ben Murdocha3f7b4e2013-07-24 10:36:34 +01002405 // Go back, but don't commit yet. Check that we can't delete the current
2406 // and pending entries.
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002407 controller.GoBack();
Ben Murdocha3f7b4e2013-07-24 10:36:34 +01002408 EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
2409 EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 2));
2410
2411 // Now commit and delete the last entry.
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002412 test_rvh()->SendNavigate(3, url4);
Ben Murdocha3f7b4e2013-07-24 10:36:34 +01002413 EXPECT_TRUE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002414 EXPECT_EQ(4, controller.GetEntryCount());
2415 EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
2416 EXPECT_FALSE(controller.GetPendingEntry());
2417
2418 // Remove an entry which is not the last committed one.
Ben Murdocha3f7b4e2013-07-24 10:36:34 +01002419 EXPECT_TRUE(controller.RemoveEntryAtIndex(0));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002420 EXPECT_EQ(3, controller.GetEntryCount());
2421 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
2422 EXPECT_FALSE(controller.GetPendingEntry());
2423
2424 // Remove the 2 remaining entries.
2425 controller.RemoveEntryAtIndex(1);
2426 controller.RemoveEntryAtIndex(0);
2427
2428 // This should leave us with only the last committed entry.
2429 EXPECT_EQ(1, controller.GetEntryCount());
2430 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
2431}
2432
2433// Tests the transient entry, making sure it goes away with all navigations.
2434TEST_F(NavigationControllerTest, TransientEntry) {
2435 NavigationControllerImpl& controller = controller_impl();
2436 TestNotificationTracker notifications;
2437 RegisterForAllNavNotifications(&notifications, &controller);
2438
2439 const GURL url0("http://foo/0");
2440 const GURL url1("http://foo/1");
2441 const GURL url2("http://foo/2");
2442 const GURL url3("http://foo/3");
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002443 const GURL url3_ref("http://foo/3#bar");
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002444 const GURL url4("http://foo/4");
2445 const GURL transient_url("http://foo/transient");
2446
2447 controller.LoadURL(
2448 url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2449 test_rvh()->SendNavigate(0, url0);
2450 controller.LoadURL(
2451 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2452 test_rvh()->SendNavigate(1, url1);
2453
2454 notifications.Reset();
2455
2456 // Adding a transient with no pending entry.
2457 NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
2458 transient_entry->SetURL(transient_url);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002459 controller.SetTransientEntry(transient_entry);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002460
2461 // We should not have received any notifications.
2462 EXPECT_EQ(0U, notifications.size());
2463
2464 // Check our state.
2465 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
2466 EXPECT_EQ(controller.GetEntryCount(), 3);
2467 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
2468 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
2469 EXPECT_TRUE(controller.GetLastCommittedEntry());
2470 EXPECT_FALSE(controller.GetPendingEntry());
2471 EXPECT_TRUE(controller.CanGoBack());
2472 EXPECT_FALSE(controller.CanGoForward());
2473 EXPECT_EQ(contents()->GetMaxPageID(), 1);
2474
2475 // Navigate.
2476 controller.LoadURL(
2477 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2478 test_rvh()->SendNavigate(2, url2);
2479
2480 // We should have navigated, transient entry should be gone.
2481 EXPECT_EQ(url2, controller.GetActiveEntry()->GetURL());
2482 EXPECT_EQ(controller.GetEntryCount(), 3);
2483
2484 // Add a transient again, then navigate with no pending entry this time.
2485 transient_entry = new NavigationEntryImpl;
2486 transient_entry->SetURL(transient_url);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002487 controller.SetTransientEntry(transient_entry);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002488 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
2489 test_rvh()->SendNavigate(3, url3);
2490 // Transient entry should be gone.
2491 EXPECT_EQ(url3, controller.GetActiveEntry()->GetURL());
2492 EXPECT_EQ(controller.GetEntryCount(), 4);
2493
2494 // Initiate a navigation, add a transient then commit navigation.
2495 controller.LoadURL(
2496 url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2497 transient_entry = new NavigationEntryImpl;
2498 transient_entry->SetURL(transient_url);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002499 controller.SetTransientEntry(transient_entry);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002500 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
2501 test_rvh()->SendNavigate(4, url4);
2502 EXPECT_EQ(url4, controller.GetActiveEntry()->GetURL());
2503 EXPECT_EQ(controller.GetEntryCount(), 5);
2504
2505 // Add a transient and go back. This should simply remove the transient.
2506 transient_entry = new NavigationEntryImpl;
2507 transient_entry->SetURL(transient_url);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002508 controller.SetTransientEntry(transient_entry);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002509 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
2510 EXPECT_TRUE(controller.CanGoBack());
2511 EXPECT_FALSE(controller.CanGoForward());
2512 controller.GoBack();
2513 // Transient entry should be gone.
2514 EXPECT_EQ(url4, controller.GetActiveEntry()->GetURL());
2515 EXPECT_EQ(controller.GetEntryCount(), 5);
2516 test_rvh()->SendNavigate(3, url3);
2517
2518 // Add a transient and go to an entry before the current one.
2519 transient_entry = new NavigationEntryImpl;
2520 transient_entry->SetURL(transient_url);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002521 controller.SetTransientEntry(transient_entry);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002522 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
2523 controller.GoToIndex(1);
2524 // The navigation should have been initiated, transient entry should be gone.
2525 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
2526 // Visible entry does not update for history navigations until commit.
2527 EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
2528 test_rvh()->SendNavigate(1, url1);
2529 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
2530
2531 // Add a transient and go to an entry after the current one.
2532 transient_entry = new NavigationEntryImpl;
2533 transient_entry->SetURL(transient_url);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002534 controller.SetTransientEntry(transient_entry);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002535 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
2536 controller.GoToIndex(3);
2537 // The navigation should have been initiated, transient entry should be gone.
2538 // Because of the transient entry that is removed, going to index 3 makes us
2539 // land on url2 (which is visible after the commit).
2540 EXPECT_EQ(url2, controller.GetActiveEntry()->GetURL());
2541 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
2542 test_rvh()->SendNavigate(2, url2);
2543 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
2544
2545 // Add a transient and go forward.
2546 transient_entry = new NavigationEntryImpl;
2547 transient_entry->SetURL(transient_url);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002548 controller.SetTransientEntry(transient_entry);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002549 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
2550 EXPECT_TRUE(controller.CanGoForward());
2551 controller.GoForward();
2552 // We should have navigated, transient entry should be gone.
2553 EXPECT_EQ(url3, controller.GetActiveEntry()->GetURL());
2554 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
2555 test_rvh()->SendNavigate(3, url3);
2556 EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
2557
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002558 // Add a transient and do an in-page navigation, replacing the current entry.
2559 transient_entry = new NavigationEntryImpl;
2560 transient_entry->SetURL(transient_url);
2561 controller.SetTransientEntry(transient_entry);
2562 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
2563 test_rvh()->SendNavigate(3, url3_ref);
2564 // Transient entry should be gone.
2565 EXPECT_EQ(url3_ref, controller.GetActiveEntry()->GetURL());
2566
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002567 // Ensure the URLs are correct.
2568 EXPECT_EQ(controller.GetEntryCount(), 5);
2569 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
2570 EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), url1);
2571 EXPECT_EQ(controller.GetEntryAtIndex(2)->GetURL(), url2);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002572 EXPECT_EQ(controller.GetEntryAtIndex(3)->GetURL(), url3_ref);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002573 EXPECT_EQ(controller.GetEntryAtIndex(4)->GetURL(), url4);
2574}
2575
2576// Test that Reload initiates a new navigation to a transient entry's URL.
2577TEST_F(NavigationControllerTest, ReloadTransient) {
2578 NavigationControllerImpl& controller = controller_impl();
2579 const GURL url0("http://foo/0");
2580 const GURL url1("http://foo/1");
2581 const GURL transient_url("http://foo/transient");
2582
2583 // Load |url0|, and start a pending navigation to |url1|.
2584 controller.LoadURL(
2585 url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2586 test_rvh()->SendNavigate(0, url0);
2587 controller.LoadURL(
2588 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2589
2590 // A transient entry is added, interrupting the navigation.
2591 NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
2592 transient_entry->SetURL(transient_url);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002593 controller.SetTransientEntry(transient_entry);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002594 EXPECT_TRUE(controller.GetTransientEntry());
2595 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
2596
2597 // The page is reloaded, which should remove the pending entry for |url1| and
2598 // the transient entry for |transient_url|, and start a navigation to
2599 // |transient_url|.
2600 controller.Reload(true);
2601 EXPECT_FALSE(controller.GetTransientEntry());
2602 EXPECT_TRUE(controller.GetPendingEntry());
2603 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
2604 ASSERT_EQ(controller.GetEntryCount(), 1);
2605 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
2606
2607 // Load of |transient_url| completes.
2608 test_rvh()->SendNavigate(1, transient_url);
2609 ASSERT_EQ(controller.GetEntryCount(), 2);
2610 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
2611 EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), transient_url);
2612}
2613
2614// Tests that the URLs for renderer-initiated navigations are not displayed to
2615// the user until the navigation commits, to prevent URL spoof attacks.
2616// See http://crbug.com/99016.
2617TEST_F(NavigationControllerTest, DontShowRendererURLUntilCommit) {
2618 NavigationControllerImpl& controller = controller_impl();
2619 TestNotificationTracker notifications;
2620 RegisterForAllNavNotifications(&notifications, &controller);
2621
2622 const GURL url0("http://foo/0");
2623 const GURL url1("http://foo/1");
2624
2625 // For typed navigations (browser-initiated), both active and visible entries
2626 // should update before commit.
2627 controller.LoadURL(url0, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2628 EXPECT_EQ(url0, controller.GetActiveEntry()->GetURL());
2629 EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
2630 test_rvh()->SendNavigate(0, url0);
2631
2632 // For link clicks (renderer-initiated navigations), the active entry should
2633 // update before commit but the visible should not.
2634 NavigationController::LoadURLParams load_url_params(url1);
2635 load_url_params.is_renderer_initiated = true;
2636 controller.LoadURLWithParams(load_url_params);
2637 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
2638 EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
2639 EXPECT_TRUE(
2640 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
2641 is_renderer_initiated());
2642
2643 // After commit, both should be updated, and we should no longer treat the
2644 // entry as renderer-initiated.
2645 test_rvh()->SendNavigate(1, url1);
2646 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
2647 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
2648 EXPECT_FALSE(
2649 NavigationEntryImpl::FromNavigationEntry(
2650 controller.GetLastCommittedEntry())->is_renderer_initiated());
2651
2652 notifications.Reset();
2653}
2654
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01002655// Tests that the URLs for renderer-initiated navigations in new tabs are
2656// displayed to the user before commit, as long as the initial about:blank
2657// page has not been modified. If so, we must revert to showing about:blank.
2658// See http://crbug.com/9682.
2659TEST_F(NavigationControllerTest, ShowRendererURLInNewTabUntilModified) {
2660 NavigationControllerImpl& controller = controller_impl();
2661 TestNotificationTracker notifications;
2662 RegisterForAllNavNotifications(&notifications, &controller);
2663
2664 const GURL url("http://foo");
2665
2666 // For renderer-initiated navigations in new tabs (with no committed entries),
2667 // we show the pending entry's URL as long as the about:blank page is not
2668 // modified.
2669 NavigationController::LoadURLParams load_url_params(url);
2670 load_url_params.transition_type = PAGE_TRANSITION_LINK;
2671 load_url_params.is_renderer_initiated = true;
2672 controller.LoadURLWithParams(load_url_params);
2673 EXPECT_EQ(url, controller.GetActiveEntry()->GetURL());
2674 EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL());
2675 EXPECT_TRUE(
2676 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
2677 is_renderer_initiated());
2678 EXPECT_TRUE(controller.IsInitialNavigation());
2679 EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
2680
2681 // There should be no title yet.
2682 EXPECT_TRUE(contents()->GetTitle().empty());
2683
2684 // If something else modifies the contents of the about:blank page, then
2685 // we must revert to showing about:blank to avoid a URL spoof.
2686 test_rvh()->OnMessageReceived(
2687 ViewHostMsg_DidAccessInitialDocument(0));
2688 EXPECT_TRUE(test_rvh()->has_accessed_initial_document());
2689 EXPECT_FALSE(controller.GetVisibleEntry());
2690 EXPECT_EQ(url, controller.GetActiveEntry()->GetURL());
2691
2692 notifications.Reset();
2693}
2694
2695TEST_F(NavigationControllerTest, DontShowRendererURLInNewTabAfterCommit) {
2696 NavigationControllerImpl& controller = controller_impl();
2697 TestNotificationTracker notifications;
2698 RegisterForAllNavNotifications(&notifications, &controller);
2699
2700 const GURL url1("http://foo/eh");
2701 const GURL url2("http://foo/bee");
2702
2703 // For renderer-initiated navigations in new tabs (with no committed entries),
2704 // we show the pending entry's URL as long as the about:blank page is not
2705 // modified.
2706 NavigationController::LoadURLParams load_url_params(url1);
2707 load_url_params.transition_type = PAGE_TRANSITION_LINK;
2708 load_url_params.is_renderer_initiated = true;
2709 controller.LoadURLWithParams(load_url_params);
2710 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
2711 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
2712 EXPECT_TRUE(
2713 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
2714 is_renderer_initiated());
2715 EXPECT_TRUE(controller.IsInitialNavigation());
2716 EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
2717
2718 // Simulate a commit and then starting a new pending navigation.
2719 test_rvh()->SendNavigate(0, url1);
2720 NavigationController::LoadURLParams load_url2_params(url2);
2721 load_url2_params.transition_type = PAGE_TRANSITION_LINK;
2722 load_url2_params.is_renderer_initiated = true;
2723 controller.LoadURLWithParams(load_url2_params);
2724
2725 // We should not consider this an initial navigation, and thus should
2726 // not show the pending URL.
2727 EXPECT_FALSE(test_rvh()->has_accessed_initial_document());
2728 EXPECT_FALSE(controller.IsInitialNavigation());
2729 EXPECT_TRUE(controller.GetVisibleEntry());
2730 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
2731
2732 notifications.Reset();
2733}
2734
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002735// Tests that IsInPageNavigation returns appropriate results. Prevents
2736// regression for bug 1126349.
2737TEST_F(NavigationControllerTest, IsInPageNavigation) {
2738 NavigationControllerImpl& controller = controller_impl();
2739 // Navigate to URL with no refs.
2740 const GURL url("http://www.google.com/home.html");
2741 test_rvh()->SendNavigate(0, url);
2742
2743 // Reloading the page is not an in-page navigation.
2744 EXPECT_FALSE(controller.IsURLInPageNavigation(url));
2745 const GURL other_url("http://www.google.com/add.html");
2746 EXPECT_FALSE(controller.IsURLInPageNavigation(other_url));
2747 const GURL url_with_ref("http://www.google.com/home.html#my_ref");
2748 EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref));
2749
2750 // Navigate to URL with refs.
2751 test_rvh()->SendNavigate(1, url_with_ref);
2752
2753 // Reloading the page is not an in-page navigation.
2754 EXPECT_FALSE(controller.IsURLInPageNavigation(url_with_ref));
2755 EXPECT_FALSE(controller.IsURLInPageNavigation(url));
2756 EXPECT_FALSE(controller.IsURLInPageNavigation(other_url));
2757 const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref");
Ben Murdochbb1529c2013-08-08 10:24:53 +01002758 EXPECT_TRUE(controller.IsURLInPageNavigation(other_url_with_ref));
2759
2760 // Going to the same url again will be considered in-page
2761 // if the renderer says it is even if the navigation type isn't IN_PAGE.
2762 EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref, true,
2763 NAVIGATION_TYPE_UNKNOWN));
2764
2765 // Going back to the non ref url will be considered in-page if the navigation
2766 // type is IN_PAGE.
2767 EXPECT_TRUE(controller.IsURLInPageNavigation(url, true,
2768 NAVIGATION_TYPE_IN_PAGE));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002769}
2770
2771// Some pages can have subframes with the same base URL (minus the reference) as
2772// the main page. Even though this is hard, it can happen, and we don't want
2773// these subframe navigations to affect the toplevel document. They should
2774// instead be ignored. http://crbug.com/5585
2775TEST_F(NavigationControllerTest, SameSubframe) {
2776 NavigationControllerImpl& controller = controller_impl();
2777 // Navigate the main frame.
2778 const GURL url("http://www.google.com/");
2779 test_rvh()->SendNavigate(0, url);
2780
2781 // We should be at the first navigation entry.
2782 EXPECT_EQ(controller.GetEntryCount(), 1);
2783 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
2784
2785 // Navigate a subframe that would normally count as in-page.
2786 const GURL subframe("http://www.google.com/#");
2787 ViewHostMsg_FrameNavigate_Params params;
2788 params.page_id = 0;
2789 params.url = subframe;
2790 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
2791 params.should_update_history = false;
2792 params.gesture = NavigationGestureAuto;
2793 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002794 params.page_state = PageState::CreateFromURL(subframe);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002795 LoadCommittedDetails details;
2796 EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
2797
2798 // Nothing should have changed.
2799 EXPECT_EQ(controller.GetEntryCount(), 1);
2800 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
2801}
2802
2803// Make sure that on cloning a WebContentsImpl and going back needs_reload is
2804// false.
2805TEST_F(NavigationControllerTest, CloneAndGoBack) {
2806 NavigationControllerImpl& controller = controller_impl();
2807 const GURL url1("http://foo1");
2808 const GURL url2("http://foo2");
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01002809 const string16 title(ASCIIToUTF16("Title"));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002810
2811 NavigateAndCommit(url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01002812 controller.GetActiveEntry()->SetTitle(title);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002813 NavigateAndCommit(url2);
2814
2815 scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
2816
2817 ASSERT_EQ(2, clone->GetController().GetEntryCount());
2818 EXPECT_TRUE(clone->GetController().NeedsReload());
2819 clone->GetController().GoBack();
2820 // Navigating back should have triggered needs_reload_ to go false.
2821 EXPECT_FALSE(clone->GetController().NeedsReload());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01002822
2823 // Ensure that the pending URL and its title are visible.
2824 EXPECT_EQ(url1, clone->GetController().GetVisibleEntry()->GetURL());
2825 EXPECT_EQ(title, clone->GetTitle());
2826}
2827
2828// Make sure that reloading a cloned tab doesn't change its pending entry index.
2829// See http://crbug.com/234491.
2830TEST_F(NavigationControllerTest, CloneAndReload) {
2831 NavigationControllerImpl& controller = controller_impl();
2832 const GURL url1("http://foo1");
2833 const GURL url2("http://foo2");
2834 const string16 title(ASCIIToUTF16("Title"));
2835
2836 NavigateAndCommit(url1);
2837 controller.GetActiveEntry()->SetTitle(title);
2838 NavigateAndCommit(url2);
2839
2840 scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
2841 clone->GetController().LoadIfNecessary();
2842
2843 ASSERT_EQ(2, clone->GetController().GetEntryCount());
2844 EXPECT_EQ(1, clone->GetController().GetPendingEntryIndex());
2845
2846 clone->GetController().Reload(true);
2847 EXPECT_EQ(1, clone->GetController().GetPendingEntryIndex());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002848}
2849
2850// Make sure that cloning a WebContentsImpl doesn't copy interstitials.
2851TEST_F(NavigationControllerTest, CloneOmitsInterstitials) {
2852 NavigationControllerImpl& controller = controller_impl();
2853 const GURL url1("http://foo1");
2854 const GURL url2("http://foo2");
2855
2856 NavigateAndCommit(url1);
2857 NavigateAndCommit(url2);
2858
2859 // Add an interstitial entry. Should be deleted with controller.
2860 NavigationEntryImpl* interstitial_entry = new NavigationEntryImpl();
2861 interstitial_entry->set_page_type(PAGE_TYPE_INTERSTITIAL);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00002862 controller.SetTransientEntry(interstitial_entry);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002863
2864 scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
2865
2866 ASSERT_EQ(2, clone->GetController().GetEntryCount());
2867}
2868
2869// Tests a subframe navigation while a toplevel navigation is pending.
2870// http://crbug.com/43967
2871TEST_F(NavigationControllerTest, SubframeWhilePending) {
2872 NavigationControllerImpl& controller = controller_impl();
2873 // Load the first page.
2874 const GURL url1("http://foo/");
2875 NavigateAndCommit(url1);
2876
2877 // Now start a pending load to a totally different page, but don't commit it.
2878 const GURL url2("http://bar/");
2879 controller.LoadURL(
2880 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2881
2882 // Send a subframe update from the first page, as if one had just
2883 // automatically loaded. Auto subframes don't increment the page ID.
2884 const GURL url1_sub("http://foo/subframe");
2885 ViewHostMsg_FrameNavigate_Params params;
2886 params.page_id = controller.GetLastCommittedEntry()->GetPageID();
2887 params.url = url1_sub;
2888 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
2889 params.should_update_history = false;
2890 params.gesture = NavigationGestureAuto;
2891 params.is_post = false;
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01002892 params.page_state = PageState::CreateFromURL(url1_sub);
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002893 LoadCommittedDetails details;
2894
2895 // This should return false meaning that nothing was actually updated.
2896 EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
2897
2898 // The notification should have updated the last committed one, and not
2899 // the pending load.
2900 EXPECT_EQ(url1, controller.GetLastCommittedEntry()->GetURL());
2901
2902 // The active entry should be unchanged by the subframe load.
2903 EXPECT_EQ(url2, controller.GetActiveEntry()->GetURL());
2904}
2905
2906// Test CopyStateFrom with 2 urls, the first selected and nothing in the target.
2907TEST_F(NavigationControllerTest, CopyStateFrom) {
2908 NavigationControllerImpl& controller = controller_impl();
2909 const GURL url1("http://foo1");
2910 const GURL url2("http://foo2");
2911
2912 NavigateAndCommit(url1);
2913 NavigateAndCommit(url2);
2914 controller.GoBack();
2915 contents()->CommitPendingNavigation();
2916
2917 scoped_ptr<TestWebContents> other_contents(
2918 static_cast<TestWebContents*>(CreateTestWebContents()));
2919 NavigationControllerImpl& other_controller = other_contents->GetController();
2920 other_controller.CopyStateFrom(controller);
2921
2922 // other_controller should now contain 2 urls.
2923 ASSERT_EQ(2, other_controller.GetEntryCount());
2924 // We should be looking at the first one.
2925 ASSERT_EQ(0, other_controller.GetCurrentEntryIndex());
2926
2927 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2928 EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
2929 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
2930 // This is a different site than url1, so the IDs start again at 0.
2931 EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID());
2932
2933 // The max page ID map should be copied over and updated with the max page ID
2934 // from the current tab.
2935 SiteInstance* instance1 =
2936 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
2937 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
Ben Murdochca12bfa2013-07-23 11:17:05 +01002938
2939 // Ensure the SessionStorageNamespaceMaps are the same size and have
2940 // the same partitons loaded.
2941 //
2942 // TODO(ajwong): We should load a url from a different partition earlier
2943 // to make sure this map has more than one entry.
2944 const SessionStorageNamespaceMap& session_storage_namespace_map =
2945 controller.GetSessionStorageNamespaceMap();
2946 const SessionStorageNamespaceMap& other_session_storage_namespace_map =
2947 other_controller.GetSessionStorageNamespaceMap();
2948 EXPECT_EQ(session_storage_namespace_map.size(),
2949 other_session_storage_namespace_map.size());
2950 for (SessionStorageNamespaceMap::const_iterator it =
2951 session_storage_namespace_map.begin();
2952 it != session_storage_namespace_map.end();
2953 ++it) {
2954 SessionStorageNamespaceMap::const_iterator other =
2955 other_session_storage_namespace_map.find(it->first);
2956 EXPECT_TRUE(other != other_session_storage_namespace_map.end());
2957 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +00002958}
2959
2960// Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
2961TEST_F(NavigationControllerTest, CopyStateFromAndPrune) {
2962 NavigationControllerImpl& controller = controller_impl();
2963 const GURL url1("http://foo/1");
2964 const GURL url2("http://foo/2");
2965 const GURL url3("http://foo/3");
2966
2967 NavigateAndCommit(url1);
2968 NavigateAndCommit(url2);
2969
2970 // First two entries should have the same SiteInstance.
2971 SiteInstance* instance1 =
2972 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0));
2973 SiteInstance* instance2 =
2974 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1));
2975 EXPECT_EQ(instance1, instance2);
2976 EXPECT_EQ(0, controller.GetEntryAtIndex(0)->GetPageID());
2977 EXPECT_EQ(1, controller.GetEntryAtIndex(1)->GetPageID());
2978 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1));
2979
2980 scoped_ptr<TestWebContents> other_contents(
2981 static_cast<TestWebContents*>(CreateTestWebContents()));
2982 NavigationControllerImpl& other_controller = other_contents->GetController();
2983 other_contents->NavigateAndCommit(url3);
2984 other_contents->ExpectSetHistoryLengthAndPrune(
2985 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
2986 other_controller.GetEntryAtIndex(0)->GetPageID());
2987 other_controller.CopyStateFromAndPrune(&controller);
2988
2989 // other_controller should now contain the 3 urls: url1, url2 and url3.
2990
2991 ASSERT_EQ(3, other_controller.GetEntryCount());
2992
2993 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
2994
2995 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2996 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
2997 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
2998 EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
2999 EXPECT_EQ(1, other_controller.GetEntryAtIndex(1)->GetPageID());
3000 EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
3001
3002 // A new SiteInstance should be used for the new tab.
3003 SiteInstance* instance3 =
3004 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
3005 EXPECT_NE(instance3, instance1);
3006
3007 // The max page ID map should be copied over and updated with the max page ID
3008 // from the current tab.
3009 EXPECT_EQ(1, other_contents->GetMaxPageIDForSiteInstance(instance1));
3010 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance3));
3011}
3012
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003013// Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry in
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003014// the target.
3015TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) {
3016 NavigationControllerImpl& controller = controller_impl();
3017 const GURL url1("http://foo1");
3018 const GURL url2("http://foo2");
3019 const GURL url3("http://foo3");
3020
3021 NavigateAndCommit(url1);
3022 NavigateAndCommit(url2);
3023 controller.GoBack();
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003024 contents()->CommitPendingNavigation();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003025
3026 scoped_ptr<TestWebContents> other_contents(
3027 static_cast<TestWebContents*>(CreateTestWebContents()));
3028 NavigationControllerImpl& other_controller = other_contents->GetController();
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003029 other_contents->NavigateAndCommit(url3);
3030 other_contents->ExpectSetHistoryLengthAndPrune(
3031 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
3032 other_controller.GetEntryAtIndex(0)->GetPageID());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003033 other_controller.CopyStateFromAndPrune(&controller);
3034
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003035 // other_controller should now contain: url1, url3
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003036
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003037 ASSERT_EQ(2, other_controller.GetEntryCount());
3038 ASSERT_EQ(1, other_controller.GetCurrentEntryIndex());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003039
3040 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003041 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
3042 EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID());
3043
3044 // The max page ID map should be copied over and updated with the max page ID
3045 // from the current tab.
3046 SiteInstance* instance1 =
3047 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
3048 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3049}
3050
3051// Test CopyStateFromAndPrune with 2 urls, the last selected and 2 entries in
3052// the target.
3053TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) {
3054 NavigationControllerImpl& controller = controller_impl();
3055 const GURL url1("http://foo1");
3056 const GURL url2("http://foo2");
3057 const GURL url3("http://foo3");
3058 const GURL url4("http://foo4");
3059
3060 NavigateAndCommit(url1);
3061 NavigateAndCommit(url2);
3062
3063 scoped_ptr<TestWebContents> other_contents(
3064 static_cast<TestWebContents*>(CreateTestWebContents()));
3065 NavigationControllerImpl& other_controller = other_contents->GetController();
3066 other_contents->NavigateAndCommit(url3);
3067 other_contents->NavigateAndCommit(url4);
3068 other_contents->ExpectSetHistoryLengthAndPrune(
3069 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1)), 2,
3070 other_controller.GetEntryAtIndex(0)->GetPageID());
3071 other_controller.CopyStateFromAndPrune(&controller);
3072
3073 // other_controller should now contain: url1, url2, url4
3074
3075 ASSERT_EQ(3, other_controller.GetEntryCount());
3076 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
3077
3078 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3079 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
3080 EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
3081
3082 // The max page ID map should be copied over and updated with the max page ID
3083 // from the current tab.
3084 SiteInstance* instance1 =
3085 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
3086 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3087}
3088
3089// Test CopyStateFromAndPrune with 2 urls, 2 entries in the target, with
3090// not the last entry selected in the target.
3091TEST_F(NavigationControllerTest, CopyStateFromAndPruneNotLast) {
3092 NavigationControllerImpl& controller = controller_impl();
3093 const GURL url1("http://foo1");
3094 const GURL url2("http://foo2");
3095 const GURL url3("http://foo3");
3096 const GURL url4("http://foo4");
3097
3098 NavigateAndCommit(url1);
3099 NavigateAndCommit(url2);
3100
3101 scoped_ptr<TestWebContents> other_contents(
3102 static_cast<TestWebContents*>(CreateTestWebContents()));
3103 NavigationControllerImpl& other_controller = other_contents->GetController();
3104 other_contents->NavigateAndCommit(url3);
3105 other_contents->NavigateAndCommit(url4);
3106 other_controller.GoBack();
3107 other_contents->CommitPendingNavigation();
3108 other_contents->ExpectSetHistoryLengthAndPrune(
3109 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
3110 other_controller.GetEntryAtIndex(0)->GetPageID());
3111 other_controller.CopyStateFromAndPrune(&controller);
3112
3113 // other_controller should now contain: url1, url2, url3
3114
3115 ASSERT_EQ(3, other_controller.GetEntryCount());
3116 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
3117
3118 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3119 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
3120 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
3121
3122 // The max page ID map should be copied over and updated with the max page ID
3123 // from the current tab.
3124 SiteInstance* instance1 =
3125 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
3126 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3127}
3128
3129// Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry plus
3130// a pending entry in the target.
3131TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending) {
3132 NavigationControllerImpl& controller = controller_impl();
3133 const GURL url1("http://foo1");
3134 const GURL url2("http://foo2");
3135 const GURL url3("http://foo3");
3136 const GURL url4("http://foo4");
3137
3138 NavigateAndCommit(url1);
3139 NavigateAndCommit(url2);
3140 controller.GoBack();
3141 contents()->CommitPendingNavigation();
3142
3143 scoped_ptr<TestWebContents> other_contents(
3144 static_cast<TestWebContents*>(CreateTestWebContents()));
3145 NavigationControllerImpl& other_controller = other_contents->GetController();
3146 other_contents->NavigateAndCommit(url3);
3147 other_controller.LoadURL(
3148 url4, Referrer(), PAGE_TRANSITION_TYPED, std::string());
3149 other_contents->ExpectSetHistoryLengthAndPrune(
3150 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
3151 other_controller.GetEntryAtIndex(0)->GetPageID());
3152 other_controller.CopyStateFromAndPrune(&controller);
3153
3154 // other_controller should now contain url1, url3, and a pending entry
3155 // for url4.
3156
3157 ASSERT_EQ(2, other_controller.GetEntryCount());
3158 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
3159
3160 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3161 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
3162
3163 // And there should be a pending entry for url4.
3164 ASSERT_TRUE(other_controller.GetPendingEntry());
3165 EXPECT_EQ(url4, other_controller.GetPendingEntry()->GetURL());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003166
3167 // The max page ID map should be copied over and updated with the max page ID
3168 // from the current tab.
3169 SiteInstance* instance1 =
3170 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
3171 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3172}
3173
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003174// Test CopyStateFromAndPrune with 1 url in the source, 1 entry and a pending
3175// client redirect entry (with the same page ID) in the target. This used to
3176// crash because the last committed entry would be pruned but max_page_id
3177// remembered the page ID (http://crbug.com/234809).
3178TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending2) {
3179 NavigationControllerImpl& controller = controller_impl();
3180 const GURL url1("http://foo1");
3181 const GURL url2a("http://foo2/a");
3182 const GURL url2b("http://foo2/b");
3183
3184 NavigateAndCommit(url1);
3185
3186 scoped_ptr<TestWebContents> other_contents(
3187 static_cast<TestWebContents*>(CreateTestWebContents()));
3188 NavigationControllerImpl& other_controller = other_contents->GetController();
3189 other_contents->NavigateAndCommit(url2a);
3190 // Simulate a client redirect, which has the same page ID as entry 2a.
3191 other_controller.LoadURL(
3192 url2b, Referrer(), PAGE_TRANSITION_LINK, std::string());
3193 other_controller.GetPendingEntry()->SetPageID(
3194 other_controller.GetLastCommittedEntry()->GetPageID());
3195
3196 other_contents->ExpectSetHistoryLengthAndPrune(
3197 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1,
3198 other_controller.GetEntryAtIndex(0)->GetPageID());
3199 other_controller.CopyStateFromAndPrune(&controller);
3200
3201 // other_controller should now contain url1, url2a, and a pending entry
3202 // for url2b.
3203
3204 ASSERT_EQ(2, other_controller.GetEntryCount());
3205 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
3206
3207 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
3208 EXPECT_EQ(url2a, other_controller.GetEntryAtIndex(1)->GetURL());
3209
3210 // And there should be a pending entry for url4.
3211 ASSERT_TRUE(other_controller.GetPendingEntry());
3212 EXPECT_EQ(url2b, other_controller.GetPendingEntry()->GetURL());
3213
3214 // Let the pending entry commit.
3215 other_contents->CommitPendingNavigation();
3216
3217 // The max page ID map should be copied over and updated with the max page ID
3218 // from the current tab.
3219 SiteInstance* instance1 =
3220 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1));
3221 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3222}
3223
3224// Test CopyStateFromAndPrune with 2 urls, a back navigation pending in the
3225// source, and 1 entry in the target. The back pending entry should be ignored.
3226TEST_F(NavigationControllerTest, CopyStateFromAndPruneSourcePending) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003227 NavigationControllerImpl& controller = controller_impl();
3228 const GURL url1("http://foo1");
3229 const GURL url2("http://foo2");
3230 const GURL url3("http://foo3");
3231
3232 NavigateAndCommit(url1);
3233 NavigateAndCommit(url2);
3234 controller.GoBack();
3235
3236 scoped_ptr<TestWebContents> other_contents(
3237 static_cast<TestWebContents*>(CreateTestWebContents()));
3238 NavigationControllerImpl& other_controller = other_contents->GetController();
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003239 other_contents->NavigateAndCommit(url3);
3240 other_contents->ExpectSetHistoryLengthAndPrune(
3241 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
3242 other_controller.GetEntryAtIndex(0)->GetPageID());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003243 other_controller.CopyStateFromAndPrune(&controller);
3244
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003245 // other_controller should now contain: url1, url2, url3
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003246
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003247 ASSERT_EQ(3, other_controller.GetEntryCount());
3248 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003249
3250 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003251 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
3252 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
3253 EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003254
3255 // The max page ID map should be copied over and updated with the max page ID
3256 // from the current tab.
3257 SiteInstance* instance1 =
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003258 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003259 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
3260}
3261
3262// Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest,
3263// when the max entry count is 3. We should prune one entry.
3264TEST_F(NavigationControllerTest, CopyStateFromAndPruneMaxEntries) {
3265 NavigationControllerImpl& controller = controller_impl();
3266 size_t original_count = NavigationControllerImpl::max_entry_count();
3267 const int kMaxEntryCount = 3;
3268
3269 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
3270
3271 const GURL url1("http://foo/1");
3272 const GURL url2("http://foo/2");
3273 const GURL url3("http://foo/3");
3274 const GURL url4("http://foo/4");
3275
3276 // Create a PrunedListener to observe prune notifications.
3277 PrunedListener listener(&controller);
3278
3279 NavigateAndCommit(url1);
3280 NavigateAndCommit(url2);
3281 NavigateAndCommit(url3);
3282
3283 scoped_ptr<TestWebContents> other_contents(
3284 static_cast<TestWebContents*>(CreateTestWebContents()));
3285 NavigationControllerImpl& other_controller = other_contents->GetController();
3286 other_contents->NavigateAndCommit(url4);
3287 other_contents->ExpectSetHistoryLengthAndPrune(
3288 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
3289 other_controller.GetEntryAtIndex(0)->GetPageID());
3290 other_controller.CopyStateFromAndPrune(&controller);
3291
3292 // We should have received a pruned notification.
3293 EXPECT_EQ(1, listener.notification_count_);
3294 EXPECT_TRUE(listener.details_.from_front);
3295 EXPECT_EQ(1, listener.details_.count);
3296
3297 // other_controller should now contain only 3 urls: url2, url3 and url4.
3298
3299 ASSERT_EQ(3, other_controller.GetEntryCount());
3300
3301 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
3302
3303 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(0)->GetURL());
3304 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
3305 EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
3306 EXPECT_EQ(1, other_controller.GetEntryAtIndex(0)->GetPageID());
3307 EXPECT_EQ(2, other_controller.GetEntryAtIndex(1)->GetPageID());
3308 EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
3309
3310 NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
3311}
3312
3313// Tests that navigations initiated from the page (with the history object)
3314// work as expected without navigation entries.
3315TEST_F(NavigationControllerTest, HistoryNavigate) {
3316 NavigationControllerImpl& controller = controller_impl();
3317 const GURL url1("http://foo/1");
3318 const GURL url2("http://foo/2");
3319 const GURL url3("http://foo/3");
3320
3321 NavigateAndCommit(url1);
3322 NavigateAndCommit(url2);
3323 NavigateAndCommit(url3);
3324 controller.GoBack();
3325 contents()->CommitPendingNavigation();
3326
3327 // Simulate the page calling history.back(), it should not create a pending
3328 // entry.
3329 contents()->OnGoToEntryAtOffset(-1);
3330 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3331 // The actual cross-navigation is suspended until the current RVH tells us
3332 // it unloaded, simulate that.
3333 contents()->ProceedWithCrossSiteNavigation();
3334 // Also make sure we told the page to navigate.
3335 const IPC::Message* message =
3336 process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
3337 ASSERT_TRUE(message != NULL);
3338 Tuple1<ViewMsg_Navigate_Params> nav_params;
3339 ViewMsg_Navigate::Read(message, &nav_params);
3340 EXPECT_EQ(url1, nav_params.a.url);
3341 process()->sink().ClearMessages();
3342
3343 // Now test history.forward()
3344 contents()->OnGoToEntryAtOffset(1);
3345 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3346 // The actual cross-navigation is suspended until the current RVH tells us
3347 // it unloaded, simulate that.
3348 contents()->ProceedWithCrossSiteNavigation();
3349 message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
3350 ASSERT_TRUE(message != NULL);
3351 ViewMsg_Navigate::Read(message, &nav_params);
3352 EXPECT_EQ(url3, nav_params.a.url);
3353 process()->sink().ClearMessages();
3354
3355 // Make sure an extravagant history.go() doesn't break.
3356 contents()->OnGoToEntryAtOffset(120); // Out of bounds.
3357 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3358 message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
3359 EXPECT_TRUE(message == NULL);
3360}
3361
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003362// Test call to PruneAllButVisible for the only entry.
3363TEST_F(NavigationControllerTest, PruneAllButVisibleForSingle) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003364 NavigationControllerImpl& controller = controller_impl();
3365 const GURL url1("http://foo1");
3366 NavigateAndCommit(url1);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003367
3368 contents()->ExpectSetHistoryLengthAndPrune(
3369 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0,
3370 controller.GetEntryAtIndex(0)->GetPageID());
3371
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003372 controller.PruneAllButVisible();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003373
3374 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3375 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1);
3376}
3377
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003378// Test call to PruneAllButVisible for first entry.
3379TEST_F(NavigationControllerTest, PruneAllButVisibleForFirst) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003380 NavigationControllerImpl& controller = controller_impl();
3381 const GURL url1("http://foo/1");
3382 const GURL url2("http://foo/2");
3383 const GURL url3("http://foo/3");
3384
3385 NavigateAndCommit(url1);
3386 NavigateAndCommit(url2);
3387 NavigateAndCommit(url3);
3388 controller.GoBack();
3389 controller.GoBack();
3390 contents()->CommitPendingNavigation();
3391
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003392 contents()->ExpectSetHistoryLengthAndPrune(
3393 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0,
3394 controller.GetEntryAtIndex(0)->GetPageID());
3395
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003396 controller.PruneAllButVisible();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003397
3398 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3399 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1);
3400}
3401
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003402// Test call to PruneAllButVisible for intermediate entry.
3403TEST_F(NavigationControllerTest, PruneAllButVisibleForIntermediate) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003404 NavigationControllerImpl& controller = controller_impl();
3405 const GURL url1("http://foo/1");
3406 const GURL url2("http://foo/2");
3407 const GURL url3("http://foo/3");
3408
3409 NavigateAndCommit(url1);
3410 NavigateAndCommit(url2);
3411 NavigateAndCommit(url3);
3412 controller.GoBack();
3413 contents()->CommitPendingNavigation();
3414
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003415 contents()->ExpectSetHistoryLengthAndPrune(
3416 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1)), 0,
3417 controller.GetEntryAtIndex(1)->GetPageID());
3418
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003419 controller.PruneAllButVisible();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003420
3421 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3422 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url2);
3423}
3424
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003425// Test call to PruneAllButVisible for a pending entry that is not yet in the
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003426// list of entries.
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003427TEST_F(NavigationControllerTest, PruneAllButVisibleForPendingNotInList) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003428 NavigationControllerImpl& controller = controller_impl();
3429 const GURL url1("http://foo/1");
3430 const GURL url2("http://foo/2");
3431 const GURL url3("http://foo/3");
3432
3433 NavigateAndCommit(url1);
3434 NavigateAndCommit(url2);
3435
3436 // Create a pending entry that is not in the entry list.
3437 controller.LoadURL(
3438 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
3439 EXPECT_TRUE(controller.GetPendingEntry());
3440 EXPECT_EQ(2, controller.GetEntryCount());
3441
3442 contents()->ExpectSetHistoryLengthAndPrune(
3443 NULL, 0, controller.GetPendingEntry()->GetPageID());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003444 controller.PruneAllButVisible();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003445
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003446 // We should only have the last committed and pending entries at this point,
3447 // and the pending entry should still not be in the entry list.
3448 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
3449 EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003450 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3451 EXPECT_TRUE(controller.GetPendingEntry());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003452 EXPECT_EQ(1, controller.GetEntryCount());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003453
3454 // Try to commit the pending entry.
3455 test_rvh()->SendNavigate(2, url3);
3456 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3457 EXPECT_FALSE(controller.GetPendingEntry());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003458 EXPECT_EQ(2, controller.GetEntryCount());
3459 EXPECT_EQ(url3, controller.GetEntryAtIndex(1)->GetURL());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003460}
3461
3462// Test to ensure that when we do a history navigation back to the current
3463// committed page (e.g., going forward to a slow-loading page, then pressing
3464// the back button), we just stop the navigation to prevent the throbber from
3465// running continuously. Otherwise, the RenderViewHost forces the throbber to
3466// start, but WebKit essentially ignores the navigation and never sends a
3467// message to stop the throbber.
3468TEST_F(NavigationControllerTest, StopOnHistoryNavigationToCurrentPage) {
3469 NavigationControllerImpl& controller = controller_impl();
3470 const GURL url0("http://foo/0");
3471 const GURL url1("http://foo/1");
3472
3473 NavigateAndCommit(url0);
3474 NavigateAndCommit(url1);
3475
3476 // Go back to the original page, then forward to the slow page, then back
3477 controller.GoBack();
3478 contents()->CommitPendingNavigation();
3479
3480 controller.GoForward();
3481 EXPECT_EQ(1, controller.GetPendingEntryIndex());
3482
3483 controller.GoBack();
3484 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3485}
3486
3487TEST_F(NavigationControllerTest, IsInitialNavigation) {
3488 NavigationControllerImpl& controller = controller_impl();
3489 TestNotificationTracker notifications;
3490 RegisterForAllNavNotifications(&notifications, &controller);
3491
3492 // Initial state.
3493 EXPECT_TRUE(controller.IsInitialNavigation());
3494
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003495 // After commit, it stays false.
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003496 const GURL url1("http://foo1");
3497 test_rvh()->SendNavigate(0, url1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003498 EXPECT_EQ(1U, navigation_entry_committed_counter_);
3499 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003500 EXPECT_FALSE(controller.IsInitialNavigation());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003501
3502 // After starting a new navigation, it stays false.
3503 const GURL url2("http://foo2");
3504 controller.LoadURL(
3505 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003506}
3507
3508// Check that the favicon is not reused across a client redirect.
3509// (crbug.com/28515)
3510TEST_F(NavigationControllerTest, ClearFaviconOnRedirect) {
3511 const GURL kPageWithFavicon("http://withfavicon.html");
3512 const GURL kPageWithoutFavicon("http://withoutfavicon.html");
3513 const GURL kIconURL("http://withfavicon.ico");
3514 const gfx::Image kDefaultFavicon = FaviconStatus().image;
3515
3516 NavigationControllerImpl& controller = controller_impl();
3517 TestNotificationTracker notifications;
3518 RegisterForAllNavNotifications(&notifications, &controller);
3519
3520 test_rvh()->SendNavigate(0, kPageWithFavicon);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003521 EXPECT_EQ(1U, navigation_entry_committed_counter_);
3522 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003523
3524 NavigationEntry* entry = controller.GetLastCommittedEntry();
3525 EXPECT_TRUE(entry);
3526 EXPECT_EQ(kPageWithFavicon, entry->GetURL());
3527
3528 // Simulate Chromium having set the favicon for |kPageWithFavicon|.
3529 content::FaviconStatus& favicon_status = entry->GetFavicon();
3530 favicon_status.image = CreateImage(SK_ColorWHITE);
3531 favicon_status.url = kIconURL;
3532 favicon_status.valid = true;
3533 EXPECT_FALSE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image));
3534
3535 test_rvh()->SendNavigateWithTransition(
Ben Murdoch2385ea32013-08-06 11:01:04 +01003536 0, // same page ID.
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003537 kPageWithoutFavicon,
3538 PAGE_TRANSITION_CLIENT_REDIRECT);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003539 EXPECT_EQ(1U, navigation_entry_committed_counter_);
3540 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003541
3542 entry = controller.GetLastCommittedEntry();
3543 EXPECT_TRUE(entry);
3544 EXPECT_EQ(kPageWithoutFavicon, entry->GetURL());
3545
3546 EXPECT_TRUE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image));
3547}
3548
3549// Check that the favicon is not cleared for NavigationEntries which were
3550// previously navigated to.
3551TEST_F(NavigationControllerTest, BackNavigationDoesNotClearFavicon) {
3552 const GURL kUrl1("http://www.a.com/1");
3553 const GURL kUrl2("http://www.a.com/2");
3554 const GURL kIconURL("http://www.a.com/1/favicon.ico");
3555
3556 NavigationControllerImpl& controller = controller_impl();
3557 TestNotificationTracker notifications;
3558 RegisterForAllNavNotifications(&notifications, &controller);
3559
3560 test_rvh()->SendNavigate(0, kUrl1);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003561 EXPECT_EQ(1U, navigation_entry_committed_counter_);
3562 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003563
3564 // Simulate Chromium having set the favicon for |kUrl1|.
3565 gfx::Image favicon_image = CreateImage(SK_ColorWHITE);
3566 content::NavigationEntry* entry = controller.GetLastCommittedEntry();
3567 EXPECT_TRUE(entry);
3568 content::FaviconStatus& favicon_status = entry->GetFavicon();
3569 favicon_status.image = favicon_image;
3570 favicon_status.url = kIconURL;
3571 favicon_status.valid = true;
3572
3573 // Navigate to another page and go back to the original page.
3574 test_rvh()->SendNavigate(1, kUrl2);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003575 EXPECT_EQ(1U, navigation_entry_committed_counter_);
3576 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003577 test_rvh()->SendNavigateWithTransition(
3578 0,
3579 kUrl1,
3580 PAGE_TRANSITION_FORWARD_BACK);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01003581 EXPECT_EQ(1U, navigation_entry_committed_counter_);
3582 navigation_entry_committed_counter_ = 0;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003583
3584 // Verify that the favicon for the page at |kUrl1| was not cleared.
3585 entry = controller.GetEntryAtIndex(0);
3586 EXPECT_TRUE(entry);
3587 EXPECT_EQ(kUrl1, entry->GetURL());
3588 EXPECT_TRUE(DoImagesMatch(favicon_image, entry->GetFavicon().image));
3589}
3590
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003591// The test crashes on android: http://crbug.com/170449
3592#if defined(OS_ANDROID)
3593#define MAYBE_PurgeScreenshot DISABLED_PurgeScreenshot
3594#else
3595#define MAYBE_PurgeScreenshot PurgeScreenshot
3596#endif
3597// Tests that screenshot are purged correctly.
3598TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
3599 NavigationControllerImpl& controller = controller_impl();
3600
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003601 NavigationEntryImpl* entry;
3602
3603 // Navigate enough times to make sure that some screenshots are purged.
3604 for (int i = 0; i < 12; ++i) {
3605 const GURL url(base::StringPrintf("http://foo%d/", i));
3606 NavigateAndCommit(url);
3607 EXPECT_EQ(i, controller.GetCurrentEntryIndex());
3608 }
3609
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01003610 MockScreenshotManager* screenshot_manager =
3611 new MockScreenshotManager(&controller);
3612 controller.SetScreenshotManager(screenshot_manager);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003613 for (int i = 0; i < controller.GetEntryCount(); ++i) {
3614 entry = NavigationEntryImpl::FromNavigationEntry(
3615 controller.GetEntryAtIndex(i));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01003616 screenshot_manager->TakeScreenshotFor(entry);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +01003617 EXPECT_TRUE(entry->screenshot().get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003618 }
3619
3620 NavigateAndCommit(GURL("https://foo/"));
3621 EXPECT_EQ(13, controller.GetEntryCount());
3622 entry = NavigationEntryImpl::FromNavigationEntry(
3623 controller.GetEntryAtIndex(11));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01003624 screenshot_manager->TakeScreenshotFor(entry);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003625
3626 for (int i = 0; i < 2; ++i) {
3627 entry = NavigationEntryImpl::FromNavigationEntry(
3628 controller.GetEntryAtIndex(i));
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +01003629 EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
3630 << " not purged";
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003631 }
3632
3633 for (int i = 2; i < controller.GetEntryCount() - 1; ++i) {
3634 entry = NavigationEntryImpl::FromNavigationEntry(
3635 controller.GetEntryAtIndex(i));
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +01003636 EXPECT_TRUE(entry->screenshot().get()) << "Screenshot not found for " << i;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003637 }
3638
3639 // Navigate to index 5 and then try to assign screenshot to all entries.
3640 controller.GoToIndex(5);
3641 contents()->CommitPendingNavigation();
3642 EXPECT_EQ(5, controller.GetCurrentEntryIndex());
3643 for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
3644 entry = NavigationEntryImpl::FromNavigationEntry(
3645 controller.GetEntryAtIndex(i));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01003646 screenshot_manager->TakeScreenshotFor(entry);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003647 }
3648
3649 for (int i = 10; i <= 12; ++i) {
3650 entry = NavigationEntryImpl::FromNavigationEntry(
3651 controller.GetEntryAtIndex(i));
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +01003652 EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
3653 << " not purged";
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01003654 screenshot_manager->TakeScreenshotFor(entry);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003655 }
3656
3657 // Navigate to index 7 and assign screenshot to all entries.
3658 controller.GoToIndex(7);
3659 contents()->CommitPendingNavigation();
3660 EXPECT_EQ(7, controller.GetCurrentEntryIndex());
3661 for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
3662 entry = NavigationEntryImpl::FromNavigationEntry(
3663 controller.GetEntryAtIndex(i));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01003664 screenshot_manager->TakeScreenshotFor(entry);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003665 }
3666
3667 for (int i = 0; i < 2; ++i) {
3668 entry = NavigationEntryImpl::FromNavigationEntry(
3669 controller.GetEntryAtIndex(i));
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +01003670 EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
3671 << " not purged";
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003672 }
3673
3674 // Clear all screenshots.
3675 EXPECT_EQ(13, controller.GetEntryCount());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01003676 EXPECT_EQ(10, screenshot_manager->GetScreenshotCount());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003677 controller.ClearAllScreenshots();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01003678 EXPECT_EQ(0, screenshot_manager->GetScreenshotCount());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003679 for (int i = 0; i < controller.GetEntryCount(); ++i) {
3680 entry = NavigationEntryImpl::FromNavigationEntry(
3681 controller.GetEntryAtIndex(i));
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +01003682 EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i
3683 << " not cleared";
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003684 }
3685}
3686
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01003687// Test that the navigation controller clears its session history when a
3688// navigation commits with the clear history list flag set.
3689TEST_F(NavigationControllerTest, ClearHistoryList) {
3690 const GURL url1("http://foo1");
3691 const GURL url2("http://foo2");
3692 const GURL url3("http://foo3");
3693 const GURL url4("http://foo4");
3694
3695 NavigationControllerImpl& controller = controller_impl();
3696
3697 // Create a session history with three entries, second entry is active.
3698 NavigateAndCommit(url1);
3699 NavigateAndCommit(url2);
3700 NavigateAndCommit(url3);
3701 controller.GoBack();
3702 contents()->CommitPendingNavigation();
3703 EXPECT_EQ(3, controller.GetEntryCount());
3704 EXPECT_EQ(1, controller.GetCurrentEntryIndex());
3705
3706 // Create a new pending navigation, and indicate that the session history
3707 // should be cleared.
3708 NavigationController::LoadURLParams params(url4);
3709 params.should_clear_history_list = true;
3710 controller.LoadURLWithParams(params);
3711
3712 // Verify that the pending entry correctly indicates that the session history
3713 // should be cleared.
3714 NavigationEntryImpl* entry =
3715 NavigationEntryImpl::FromNavigationEntry(
3716 controller.GetPendingEntry());
3717 ASSERT_TRUE(entry);
3718 EXPECT_TRUE(entry->should_clear_history_list());
3719
3720 // Assume that the RV correctly cleared its history and commit the navigation.
3721 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost())->
3722 set_simulate_history_list_was_cleared(true);
3723 contents()->CommitPendingNavigation();
3724
3725 // Verify that the NavigationController's session history was correctly
3726 // cleared.
3727 EXPECT_EQ(1, controller.GetEntryCount());
3728 EXPECT_EQ(0, controller.GetCurrentEntryIndex());
3729 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
3730 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
3731 EXPECT_FALSE(controller.CanGoBack());
3732 EXPECT_FALSE(controller.CanGoForward());
3733 EXPECT_EQ(url4, controller.GetActiveEntry()->GetURL());
3734}
3735
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003736/* TODO(brettw) These test pass on my local machine but fail on the XP buildbot
3737 (but not Vista) cleaning up the directory after they run.
3738 This should be fixed.
3739
3740// NavigationControllerHistoryTest ---------------------------------------------
3741
3742class NavigationControllerHistoryTest : public NavigationControllerTest {
3743 public:
3744 NavigationControllerHistoryTest()
3745 : url0("http://foo1"),
3746 url1("http://foo1"),
3747 url2("http://foo1"),
3748 profile_manager_(NULL) {
3749 }
3750
3751 virtual ~NavigationControllerHistoryTest() {
3752 // Prevent our base class from deleting the profile since profile's
3753 // lifetime is managed by profile_manager_.
3754 STLDeleteElements(&windows_);
3755 }
3756
3757 // testing::Test overrides.
3758 virtual void SetUp() {
3759 NavigationControllerTest::SetUp();
3760
3761 // Force the session service to be created.
3762 SessionService* service = new SessionService(profile());
3763 SessionServiceFactory::SetForTestProfile(profile(), service);
3764 service->SetWindowType(window_id, Browser::TYPE_TABBED);
3765 service->SetWindowBounds(window_id, gfx::Rect(0, 1, 2, 3), false);
3766 service->SetTabIndexInWindow(window_id,
3767 controller.session_id(), 0);
3768 controller.SetWindowID(window_id);
3769
3770 session_helper_.set_service(service);
3771 }
3772
3773 virtual void TearDown() {
3774 // Release profile's reference to the session service. Otherwise the file
3775 // will still be open and we won't be able to delete the directory below.
3776 session_helper_.ReleaseService(); // profile owns this
3777 SessionServiceFactory::SetForTestProfile(profile(), NULL);
3778
3779 // Make sure we wait for history to shut down before continuing. The task
3780 // we add will cause our message loop to quit once it is destroyed.
3781 HistoryService* history = HistoryServiceFactory::GetForProfiles(
3782 profile(), Profile::IMPLICIT_ACCESS);
3783 if (history) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01003784 history->SetOnBackendDestroyTask(base::MessageLoop::QuitClosure());
3785 base::MessageLoop::current()->Run();
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003786 }
3787
3788 // Do normal cleanup before deleting the profile directory below.
3789 NavigationControllerTest::TearDown();
3790
Ben Murdoch7dbb3d52013-07-17 14:55:54 +01003791 ASSERT_TRUE(base::DeleteFile(test_dir_, true));
3792 ASSERT_FALSE(base::PathExists(test_dir_));
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003793 }
3794
3795 // Deletes the current profile manager and creates a new one. Indirectly this
3796 // shuts down the history database and reopens it.
3797 void ReopenDatabase() {
3798 session_helper_.set_service(NULL);
3799 SessionServiceFactory::SetForTestProfile(profile(), NULL);
3800
3801 SessionService* service = new SessionService(profile());
3802 SessionServiceFactory::SetForTestProfile(profile(), service);
3803 session_helper_.set_service(service);
3804 }
3805
3806 void GetLastSession() {
3807 SessionServiceFactory::GetForProfile(profile())->TabClosed(
3808 controller.window_id(), controller.session_id(), false);
3809
3810 ReopenDatabase();
3811 Time close_time;
3812
3813 session_helper_.ReadWindows(&windows_);
3814 }
3815
3816 CancelableRequestConsumer consumer;
3817
3818 // URLs for testing.
3819 const GURL url0;
3820 const GURL url1;
3821 const GURL url2;
3822
3823 std::vector<SessionWindow*> windows_;
3824
3825 SessionID window_id;
3826
3827 SessionServiceTestHelper session_helper_;
3828
3829 private:
3830 ProfileManager* profile_manager_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00003831 base::FilePath test_dir_;
Torne (Richard Coles)58218062012-11-14 11:43:16 +00003832};
3833
3834// A basic test case. Navigates to a single url, and make sure the history
3835// db matches.
3836TEST_F(NavigationControllerHistoryTest, Basic) {
3837 NavigationControllerImpl& controller = controller_impl();
3838 controller.LoadURL(url0, GURL(), PAGE_TRANSITION_LINK);
3839 test_rvh()->SendNavigate(0, url0);
3840
3841 GetLastSession();
3842
3843 session_helper_.AssertSingleWindowWithSingleTab(windows_, 1);
3844 session_helper_.AssertTabEquals(0, 0, 1, *(windows_[0]->tabs[0]));
3845 TabNavigation nav1(0, url0, GURL(), string16(),
3846 webkit_glue::CreateHistoryStateForURL(url0),
3847 PAGE_TRANSITION_LINK);
3848 session_helper_.AssertNavigationEquals(nav1,
3849 windows_[0]->tabs[0]->navigations[0]);
3850}
3851
3852// Navigates to three urls, then goes back and make sure the history database
3853// is in sync.
3854TEST_F(NavigationControllerHistoryTest, NavigationThenBack) {
3855 NavigationControllerImpl& controller = controller_impl();
3856 test_rvh()->SendNavigate(0, url0);
3857 test_rvh()->SendNavigate(1, url1);
3858 test_rvh()->SendNavigate(2, url2);
3859
3860 controller.GoBack();
3861 test_rvh()->SendNavigate(1, url1);
3862
3863 GetLastSession();
3864
3865 session_helper_.AssertSingleWindowWithSingleTab(windows_, 3);
3866 session_helper_.AssertTabEquals(0, 1, 3, *(windows_[0]->tabs[0]));
3867
3868 TabNavigation nav(0, url0, GURL(), string16(),
3869 webkit_glue::CreateHistoryStateForURL(url0),
3870 PAGE_TRANSITION_LINK);
3871 session_helper_.AssertNavigationEquals(nav,
3872 windows_[0]->tabs[0]->navigations[0]);
3873 nav.set_url(url1);
3874 session_helper_.AssertNavigationEquals(nav,
3875 windows_[0]->tabs[0]->navigations[1]);
3876 nav.set_url(url2);
3877 session_helper_.AssertNavigationEquals(nav,
3878 windows_[0]->tabs[0]->navigations[2]);
3879}
3880
3881// Navigates to three urls, then goes back twice, then loads a new url.
3882TEST_F(NavigationControllerHistoryTest, NavigationPruning) {
3883 NavigationControllerImpl& controller = controller_impl();
3884 test_rvh()->SendNavigate(0, url0);
3885 test_rvh()->SendNavigate(1, url1);
3886 test_rvh()->SendNavigate(2, url2);
3887
3888 controller.GoBack();
3889 test_rvh()->SendNavigate(1, url1);
3890
3891 controller.GoBack();
3892 test_rvh()->SendNavigate(0, url0);
3893
3894 test_rvh()->SendNavigate(3, url2);
3895
3896 // Now have url0, and url2.
3897
3898 GetLastSession();
3899
3900 session_helper_.AssertSingleWindowWithSingleTab(windows_, 2);
3901 session_helper_.AssertTabEquals(0, 1, 2, *(windows_[0]->tabs[0]));
3902
3903 TabNavigation nav(0, url0, GURL(), string16(),
3904 webkit_glue::CreateHistoryStateForURL(url0),
3905 PAGE_TRANSITION_LINK);
3906 session_helper_.AssertNavigationEquals(nav,
3907 windows_[0]->tabs[0]->navigations[0]);
3908 nav.set_url(url2);
3909 session_helper_.AssertNavigationEquals(nav,
3910 windows_[0]->tabs[0]->navigations[1]);
3911}
3912*/
3913
3914} // namespace content