OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
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" | |
11 #include "base/strings/string_util.h" | |
12 #include "base/strings/utf_string_conversions.h" | |
13 #include "base/time/time.h" | |
14 #include "content/browser/renderer_host/test_render_view_host.h" | |
15 #include "content/browser/site_instance_impl.h" | |
16 #include "content/browser/web_contents/navigation_controller_impl.h" | |
17 #include "content/browser/web_contents/navigation_entry_impl.h" | |
18 #include "content/browser/web_contents/web_contents_impl.h" | |
19 #include "content/browser/web_contents/web_contents_screenshot_manager.h" | |
20 #include "content/common/view_messages.h" | |
21 #include "content/public/browser/navigation_details.h" | |
22 #include "content/public/browser/notification_registrar.h" | |
23 #include "content/public/browser/notification_types.h" | |
24 #include "content/public/browser/render_view_host.h" | |
25 #include "content/public/browser/web_contents_delegate.h" | |
26 #include "content/public/browser/web_contents_observer.h" | |
27 #include "content/public/common/page_state.h" | |
28 #include "content/public/common/url_constants.h" | |
29 #include "content/public/test/mock_render_process_host.h" | |
30 #include "content/public/test/test_notification_tracker.h" | |
31 #include "content/public/test/test_utils.h" | |
32 #include "content/test/test_web_contents.h" | |
33 #include "net/base/net_util.h" | |
34 #include "skia/ext/platform_canvas.h" | |
35 #include "testing/gtest/include/gtest/gtest.h" | |
36 | |
37 using base::Time; | |
38 | |
39 namespace { | |
40 | |
41 // Creates an image with a 1x1 SkBitmap of the specified |color|. | |
42 gfx::Image CreateImage(SkColor color) { | |
43 SkBitmap bitmap; | |
44 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1); | |
45 bitmap.allocPixels(); | |
46 bitmap.eraseColor(color); | |
47 return gfx::Image::CreateFrom1xBitmap(bitmap); | |
48 } | |
49 | |
50 // Returns true if images |a| and |b| have the same pixel data. | |
51 bool DoImagesMatch(const gfx::Image& a, const gfx::Image& b) { | |
52 // Assume that if the 1x bitmaps match, the images match. | |
53 SkBitmap a_bitmap = a.AsBitmap(); | |
54 SkBitmap b_bitmap = b.AsBitmap(); | |
55 | |
56 if (a_bitmap.width() != b_bitmap.width() || | |
57 a_bitmap.height() != b_bitmap.height()) { | |
58 return false; | |
59 } | |
60 SkAutoLockPixels a_bitmap_lock(a_bitmap); | |
61 SkAutoLockPixels b_bitmap_lock(b_bitmap); | |
62 return memcmp(a_bitmap.getPixels(), | |
63 b_bitmap.getPixels(), | |
64 a_bitmap.getSize()) == 0; | |
65 } | |
66 | |
67 class MockScreenshotManager : public content::WebContentsScreenshotManager { | |
68 public: | |
69 explicit MockScreenshotManager(content::NavigationControllerImpl* owner) | |
70 : content::WebContentsScreenshotManager(owner), | |
71 encoding_screenshot_in_progress_(false) { | |
72 } | |
73 | |
74 virtual ~MockScreenshotManager() { | |
75 } | |
76 | |
77 void TakeScreenshotFor(content::NavigationEntryImpl* entry) { | |
78 SkBitmap bitmap; | |
79 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1); | |
80 bitmap.allocPixels(); | |
81 bitmap.eraseRGB(0, 0, 0); | |
82 encoding_screenshot_in_progress_ = true; | |
83 OnScreenshotTaken(entry->GetUniqueID(), true, bitmap); | |
84 WaitUntilScreenshotIsReady(); | |
85 } | |
86 | |
87 int GetScreenshotCount() { | |
88 return content::WebContentsScreenshotManager::GetScreenshotCount(); | |
89 } | |
90 | |
91 void WaitUntilScreenshotIsReady() { | |
92 if (!encoding_screenshot_in_progress_) | |
93 return; | |
94 message_loop_runner_ = new content::MessageLoopRunner; | |
95 message_loop_runner_->Run(); | |
96 } | |
97 | |
98 private: | |
99 // Overridden from content::WebContentsScreenshotManager: | |
100 virtual void TakeScreenshotImpl( | |
101 content::RenderViewHost* host, | |
102 content::NavigationEntryImpl* entry) OVERRIDE { | |
103 } | |
104 | |
105 virtual void OnScreenshotSet(content::NavigationEntryImpl* entry) OVERRIDE { | |
106 encoding_screenshot_in_progress_ = false; | |
107 WebContentsScreenshotManager::OnScreenshotSet(entry); | |
108 if (message_loop_runner_.get()) | |
109 message_loop_runner_->Quit(); | |
110 } | |
111 | |
112 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; | |
113 bool encoding_screenshot_in_progress_; | |
114 | |
115 DISALLOW_COPY_AND_ASSIGN(MockScreenshotManager); | |
116 }; | |
117 | |
118 } // namespace | |
119 | |
120 namespace content { | |
121 | |
122 // TimeSmoother tests ---------------------------------------------------------- | |
123 | |
124 // With no duplicates, GetSmoothedTime should be the identity | |
125 // function. | |
126 TEST(TimeSmoother, Basic) { | |
127 NavigationControllerImpl::TimeSmoother smoother; | |
128 for (int64 i = 1; i < 1000; ++i) { | |
129 base::Time t = base::Time::FromInternalValue(i); | |
130 EXPECT_EQ(t, smoother.GetSmoothedTime(t)); | |
131 } | |
132 } | |
133 | |
134 // With a single duplicate and timestamps thereafter increasing by one | |
135 // microsecond, the smoothed time should always be one behind. | |
136 TEST(TimeSmoother, SingleDuplicate) { | |
137 NavigationControllerImpl::TimeSmoother smoother; | |
138 base::Time t = base::Time::FromInternalValue(1); | |
139 EXPECT_EQ(t, smoother.GetSmoothedTime(t)); | |
140 for (int64 i = 1; i < 1000; ++i) { | |
141 base::Time expected_t = base::Time::FromInternalValue(i + 1); | |
142 t = base::Time::FromInternalValue(i); | |
143 EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t)); | |
144 } | |
145 } | |
146 | |
147 // With k duplicates and timestamps thereafter increasing by one | |
148 // microsecond, the smoothed time should always be k behind. | |
149 TEST(TimeSmoother, ManyDuplicates) { | |
150 const int64 kNumDuplicates = 100; | |
151 NavigationControllerImpl::TimeSmoother smoother; | |
152 base::Time t = base::Time::FromInternalValue(1); | |
153 for (int64 i = 0; i < kNumDuplicates; ++i) { | |
154 base::Time expected_t = base::Time::FromInternalValue(i + 1); | |
155 EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t)); | |
156 } | |
157 for (int64 i = 1; i < 1000; ++i) { | |
158 base::Time expected_t = | |
159 base::Time::FromInternalValue(i + kNumDuplicates); | |
160 t = base::Time::FromInternalValue(i); | |
161 EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t)); | |
162 } | |
163 } | |
164 | |
165 // If the clock jumps far back enough after a run of duplicates, it | |
166 // should immediately jump to that value. | |
167 TEST(TimeSmoother, ClockBackwardsJump) { | |
168 const int64 kNumDuplicates = 100; | |
169 NavigationControllerImpl::TimeSmoother smoother; | |
170 base::Time t = base::Time::FromInternalValue(1000); | |
171 for (int64 i = 0; i < kNumDuplicates; ++i) { | |
172 base::Time expected_t = base::Time::FromInternalValue(i + 1000); | |
173 EXPECT_EQ(expected_t, smoother.GetSmoothedTime(t)); | |
174 } | |
175 t = base::Time::FromInternalValue(500); | |
176 EXPECT_EQ(t, smoother.GetSmoothedTime(t)); | |
177 } | |
178 | |
179 // NavigationControllerTest ---------------------------------------------------- | |
180 | |
181 class NavigationControllerTest | |
182 : public RenderViewHostImplTestHarness, | |
183 public WebContentsObserver { | |
184 public: | |
185 NavigationControllerTest() : navigation_entry_committed_counter_(0) { | |
186 } | |
187 | |
188 virtual void SetUp() OVERRIDE { | |
189 RenderViewHostImplTestHarness::SetUp(); | |
190 WebContents* web_contents = RenderViewHostImplTestHarness::web_contents(); | |
191 ASSERT_TRUE(web_contents); // The WebContents should be created by now. | |
192 WebContentsObserver::Observe(web_contents); | |
193 } | |
194 | |
195 // WebContentsObserver: | |
196 virtual void NavigateToPendingEntry( | |
197 const GURL& url, | |
198 NavigationController::ReloadType reload_type) OVERRIDE { | |
199 navigated_url_ = url; | |
200 } | |
201 | |
202 virtual void NavigationEntryCommitted( | |
203 const LoadCommittedDetails& load_details) OVERRIDE { | |
204 navigation_entry_committed_counter_++; | |
205 } | |
206 | |
207 const GURL& navigated_url() const { | |
208 return navigated_url_; | |
209 } | |
210 | |
211 NavigationControllerImpl& controller_impl() { | |
212 return static_cast<NavigationControllerImpl&>(controller()); | |
213 } | |
214 | |
215 protected: | |
216 GURL navigated_url_; | |
217 size_t navigation_entry_committed_counter_; | |
218 }; | |
219 | |
220 void RegisterForAllNavNotifications(TestNotificationTracker* tracker, | |
221 NavigationController* controller) { | |
222 tracker->ListenFor(NOTIFICATION_NAV_LIST_PRUNED, | |
223 Source<NavigationController>(controller)); | |
224 tracker->ListenFor(NOTIFICATION_NAV_ENTRY_CHANGED, | |
225 Source<NavigationController>(controller)); | |
226 } | |
227 | |
228 SiteInstance* GetSiteInstanceFromEntry(NavigationEntry* entry) { | |
229 return NavigationEntryImpl::FromNavigationEntry(entry)->site_instance(); | |
230 } | |
231 | |
232 class TestWebContentsDelegate : public WebContentsDelegate { | |
233 public: | |
234 explicit TestWebContentsDelegate() : | |
235 navigation_state_change_count_(0) {} | |
236 | |
237 int navigation_state_change_count() { | |
238 return navigation_state_change_count_; | |
239 } | |
240 | |
241 // Keep track of whether the tab has notified us of a navigation state change. | |
242 virtual void NavigationStateChanged(const WebContents* source, | |
243 unsigned changed_flags) OVERRIDE { | |
244 navigation_state_change_count_++; | |
245 } | |
246 | |
247 private: | |
248 // The number of times NavigationStateChanged has been called. | |
249 int navigation_state_change_count_; | |
250 }; | |
251 | |
252 // ----------------------------------------------------------------------------- | |
253 | |
254 TEST_F(NavigationControllerTest, Defaults) { | |
255 NavigationControllerImpl& controller = controller_impl(); | |
256 | |
257 EXPECT_FALSE(controller.GetPendingEntry()); | |
258 EXPECT_FALSE(controller.GetVisibleEntry()); | |
259 EXPECT_FALSE(controller.GetLastCommittedEntry()); | |
260 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
261 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1); | |
262 EXPECT_EQ(controller.GetEntryCount(), 0); | |
263 EXPECT_FALSE(controller.CanGoBack()); | |
264 EXPECT_FALSE(controller.CanGoForward()); | |
265 } | |
266 | |
267 TEST_F(NavigationControllerTest, GoToOffset) { | |
268 NavigationControllerImpl& controller = controller_impl(); | |
269 TestNotificationTracker notifications; | |
270 RegisterForAllNavNotifications(¬ifications, &controller); | |
271 | |
272 const int kNumUrls = 5; | |
273 std::vector<GURL> urls(kNumUrls); | |
274 for (int i = 0; i < kNumUrls; ++i) { | |
275 urls[i] = GURL(base::StringPrintf("http://www.a.com/%d", i)); | |
276 } | |
277 | |
278 test_rvh()->SendNavigate(0, urls[0]); | |
279 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
280 navigation_entry_committed_counter_ = 0; | |
281 EXPECT_EQ(urls[0], controller.GetVisibleEntry()->GetVirtualURL()); | |
282 EXPECT_FALSE(controller.CanGoBack()); | |
283 EXPECT_FALSE(controller.CanGoForward()); | |
284 EXPECT_FALSE(controller.CanGoToOffset(1)); | |
285 | |
286 for (int i = 1; i <= 4; ++i) { | |
287 test_rvh()->SendNavigate(i, urls[i]); | |
288 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
289 navigation_entry_committed_counter_ = 0; | |
290 EXPECT_EQ(urls[i], controller.GetVisibleEntry()->GetVirtualURL()); | |
291 EXPECT_TRUE(controller.CanGoToOffset(-i)); | |
292 EXPECT_FALSE(controller.CanGoToOffset(-(i + 1))); | |
293 EXPECT_FALSE(controller.CanGoToOffset(1)); | |
294 } | |
295 | |
296 // We have loaded 5 pages, and are currently at the last-loaded page. | |
297 int url_index = 4; | |
298 | |
299 enum Tests { | |
300 GO_TO_MIDDLE_PAGE = -2, | |
301 GO_FORWARDS = 1, | |
302 GO_BACKWARDS = -1, | |
303 GO_TO_BEGINNING = -2, | |
304 GO_TO_END = 4, | |
305 NUM_TESTS = 5, | |
306 }; | |
307 | |
308 const int test_offsets[NUM_TESTS] = { | |
309 GO_TO_MIDDLE_PAGE, | |
310 GO_FORWARDS, | |
311 GO_BACKWARDS, | |
312 GO_TO_BEGINNING, | |
313 GO_TO_END | |
314 }; | |
315 | |
316 for (int test = 0; test < NUM_TESTS; ++test) { | |
317 int offset = test_offsets[test]; | |
318 controller.GoToOffset(offset); | |
319 url_index += offset; | |
320 // Check that the GoToOffset will land on the expected page. | |
321 EXPECT_EQ(urls[url_index], controller.GetPendingEntry()->GetVirtualURL()); | |
322 test_rvh()->SendNavigate(url_index, urls[url_index]); | |
323 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
324 navigation_entry_committed_counter_ = 0; | |
325 // Check that we can go to any valid offset into the history. | |
326 for (size_t j = 0; j < urls.size(); ++j) | |
327 EXPECT_TRUE(controller.CanGoToOffset(j - url_index)); | |
328 // Check that we can't go beyond the beginning or end of the history. | |
329 EXPECT_FALSE(controller.CanGoToOffset(-(url_index + 1))); | |
330 EXPECT_FALSE(controller.CanGoToOffset(urls.size() - url_index)); | |
331 } | |
332 } | |
333 | |
334 TEST_F(NavigationControllerTest, LoadURL) { | |
335 NavigationControllerImpl& controller = controller_impl(); | |
336 TestNotificationTracker notifications; | |
337 RegisterForAllNavNotifications(¬ifications, &controller); | |
338 | |
339 const GURL url1("http://foo1"); | |
340 const GURL url2("http://foo2"); | |
341 | |
342 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
343 // Creating a pending notification should not have issued any of the | |
344 // notifications we're listening for. | |
345 EXPECT_EQ(0U, notifications.size()); | |
346 | |
347 // The load should now be pending. | |
348 EXPECT_EQ(controller.GetEntryCount(), 0); | |
349 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1); | |
350 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
351 EXPECT_FALSE(controller.GetLastCommittedEntry()); | |
352 ASSERT_TRUE(controller.GetPendingEntry()); | |
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 // Neither the timestamp nor the status code should have been set yet. | |
359 EXPECT_TRUE(controller.GetPendingEntry()->GetTimestamp().is_null()); | |
360 EXPECT_EQ(0, controller.GetPendingEntry()->GetHttpStatusCode()); | |
361 | |
362 // We should have gotten no notifications from the preceeding checks. | |
363 EXPECT_EQ(0U, notifications.size()); | |
364 | |
365 test_rvh()->SendNavigate(0, url1); | |
366 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
367 navigation_entry_committed_counter_ = 0; | |
368 | |
369 // The load should now be committed. | |
370 EXPECT_EQ(controller.GetEntryCount(), 1); | |
371 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
372 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
373 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
374 EXPECT_FALSE(controller.GetPendingEntry()); | |
375 ASSERT_TRUE(controller.GetVisibleEntry()); | |
376 EXPECT_FALSE(controller.CanGoBack()); | |
377 EXPECT_FALSE(controller.CanGoForward()); | |
378 EXPECT_EQ(contents()->GetMaxPageID(), 0); | |
379 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry( | |
380 controller.GetLastCommittedEntry())->bindings()); | |
381 | |
382 // The timestamp should have been set. | |
383 EXPECT_FALSE(controller.GetVisibleEntry()->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.GetVisibleEntry()); | |
395 // TODO(darin): maybe this should really be true? | |
396 EXPECT_FALSE(controller.CanGoBack()); | |
397 EXPECT_FALSE(controller.CanGoForward()); | |
398 EXPECT_EQ(contents()->GetMaxPageID(), 0); | |
399 | |
400 EXPECT_TRUE(controller.GetPendingEntry()->GetTimestamp().is_null()); | |
401 | |
402 // Simulate the beforeunload ack for the cross-site transition, and then the | |
403 // commit. | |
404 test_rvh()->SendShouldCloseACK(true); | |
405 static_cast<TestRenderViewHost*>( | |
406 contents()->GetPendingRenderViewHost())->SendNavigate(1, url2); | |
407 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
408 navigation_entry_committed_counter_ = 0; | |
409 | |
410 // The load should now be committed. | |
411 EXPECT_EQ(controller.GetEntryCount(), 2); | |
412 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1); | |
413 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
414 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
415 EXPECT_FALSE(controller.GetPendingEntry()); | |
416 ASSERT_TRUE(controller.GetVisibleEntry()); | |
417 EXPECT_TRUE(controller.CanGoBack()); | |
418 EXPECT_FALSE(controller.CanGoForward()); | |
419 EXPECT_EQ(contents()->GetMaxPageID(), 1); | |
420 | |
421 EXPECT_FALSE(controller.GetVisibleEntry()->GetTimestamp().is_null()); | |
422 } | |
423 | |
424 namespace { | |
425 | |
426 base::Time GetFixedTime(base::Time time) { | |
427 return time; | |
428 } | |
429 | |
430 } // namespace | |
431 | |
432 TEST_F(NavigationControllerTest, LoadURLSameTime) { | |
433 NavigationControllerImpl& controller = controller_impl(); | |
434 TestNotificationTracker notifications; | |
435 RegisterForAllNavNotifications(¬ifications, &controller); | |
436 | |
437 // Set the clock to always return a timestamp of 1. | |
438 controller.SetGetTimestampCallbackForTest( | |
439 base::Bind(&GetFixedTime, base::Time::FromInternalValue(1))); | |
440 | |
441 const GURL url1("http://foo1"); | |
442 const GURL url2("http://foo2"); | |
443 | |
444 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
445 | |
446 test_rvh()->SendNavigate(0, url1); | |
447 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
448 navigation_entry_committed_counter_ = 0; | |
449 | |
450 // Load another... | |
451 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
452 | |
453 // Simulate the beforeunload ack for the cross-site transition, and then the | |
454 // commit. | |
455 test_rvh()->SendShouldCloseACK(true); | |
456 test_rvh()->SendNavigate(1, url2); | |
457 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
458 navigation_entry_committed_counter_ = 0; | |
459 | |
460 // The two loads should now be committed. | |
461 ASSERT_EQ(controller.GetEntryCount(), 2); | |
462 | |
463 // Timestamps should be distinct despite the clock returning the | |
464 // same value. | |
465 EXPECT_EQ(1u, | |
466 controller.GetEntryAtIndex(0)->GetTimestamp().ToInternalValue()); | |
467 EXPECT_EQ(2u, | |
468 controller.GetEntryAtIndex(1)->GetTimestamp().ToInternalValue()); | |
469 } | |
470 | |
471 void CheckNavigationEntryMatchLoadParams( | |
472 NavigationController::LoadURLParams& load_params, | |
473 NavigationEntryImpl* entry) { | |
474 EXPECT_EQ(load_params.url, entry->GetURL()); | |
475 EXPECT_EQ(load_params.referrer.url, entry->GetReferrer().url); | |
476 EXPECT_EQ(load_params.referrer.policy, entry->GetReferrer().policy); | |
477 EXPECT_EQ(load_params.transition_type, entry->GetTransitionType()); | |
478 EXPECT_EQ(load_params.extra_headers, entry->extra_headers()); | |
479 | |
480 EXPECT_EQ(load_params.is_renderer_initiated, entry->is_renderer_initiated()); | |
481 EXPECT_EQ(load_params.base_url_for_data_url, entry->GetBaseURLForDataURL()); | |
482 if (!load_params.virtual_url_for_data_url.is_empty()) { | |
483 EXPECT_EQ(load_params.virtual_url_for_data_url, entry->GetVirtualURL()); | |
484 } | |
485 if (NavigationController::UA_OVERRIDE_INHERIT != | |
486 load_params.override_user_agent) { | |
487 bool should_override = (NavigationController::UA_OVERRIDE_TRUE == | |
488 load_params.override_user_agent); | |
489 EXPECT_EQ(should_override, entry->GetIsOverridingUserAgent()); | |
490 } | |
491 EXPECT_EQ(load_params.browser_initiated_post_data, | |
492 entry->GetBrowserInitiatedPostData()); | |
493 EXPECT_EQ(load_params.transferred_global_request_id, | |
494 entry->transferred_global_request_id()); | |
495 } | |
496 | |
497 TEST_F(NavigationControllerTest, LoadURLWithParams) { | |
498 NavigationControllerImpl& controller = controller_impl(); | |
499 | |
500 NavigationController::LoadURLParams load_params(GURL("http://foo")); | |
501 load_params.referrer = | |
502 Referrer(GURL("http://referrer"), WebKit::WebReferrerPolicyDefault); | |
503 load_params.transition_type = PAGE_TRANSITION_GENERATED; | |
504 load_params.extra_headers = "content-type: text/plain"; | |
505 load_params.load_type = NavigationController::LOAD_TYPE_DEFAULT; | |
506 load_params.is_renderer_initiated = true; | |
507 load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE; | |
508 load_params.transferred_global_request_id = GlobalRequestID(2, 3); | |
509 | |
510 controller.LoadURLWithParams(load_params); | |
511 NavigationEntryImpl* entry = | |
512 NavigationEntryImpl::FromNavigationEntry( | |
513 controller.GetPendingEntry()); | |
514 | |
515 // The timestamp should not have been set yet. | |
516 ASSERT_TRUE(entry); | |
517 EXPECT_TRUE(entry->GetTimestamp().is_null()); | |
518 | |
519 CheckNavigationEntryMatchLoadParams(load_params, entry); | |
520 } | |
521 | |
522 TEST_F(NavigationControllerTest, LoadURLWithExtraParams_Data) { | |
523 NavigationControllerImpl& controller = controller_impl(); | |
524 | |
525 NavigationController::LoadURLParams load_params( | |
526 GURL("data:text/html,dataurl")); | |
527 load_params.load_type = NavigationController::LOAD_TYPE_DATA; | |
528 load_params.base_url_for_data_url = GURL("http://foo"); | |
529 load_params.virtual_url_for_data_url = GURL(kAboutBlankURL); | |
530 load_params.override_user_agent = NavigationController::UA_OVERRIDE_FALSE; | |
531 | |
532 controller.LoadURLWithParams(load_params); | |
533 NavigationEntryImpl* entry = | |
534 NavigationEntryImpl::FromNavigationEntry( | |
535 controller.GetPendingEntry()); | |
536 | |
537 CheckNavigationEntryMatchLoadParams(load_params, entry); | |
538 } | |
539 | |
540 TEST_F(NavigationControllerTest, LoadURLWithExtraParams_HttpPost) { | |
541 NavigationControllerImpl& controller = controller_impl(); | |
542 | |
543 NavigationController::LoadURLParams load_params(GURL("https://posturl")); | |
544 load_params.transition_type = PAGE_TRANSITION_TYPED; | |
545 load_params.load_type = | |
546 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST; | |
547 load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE; | |
548 | |
549 | |
550 const unsigned char* raw_data = | |
551 reinterpret_cast<const unsigned char*>("d\n\0a2"); | |
552 const int length = 5; | |
553 std::vector<unsigned char> post_data_vector(raw_data, raw_data+length); | |
554 scoped_refptr<base::RefCountedBytes> data = | |
555 base::RefCountedBytes::TakeVector(&post_data_vector); | |
556 load_params.browser_initiated_post_data = data.get(); | |
557 | |
558 controller.LoadURLWithParams(load_params); | |
559 NavigationEntryImpl* entry = | |
560 NavigationEntryImpl::FromNavigationEntry( | |
561 controller.GetPendingEntry()); | |
562 | |
563 CheckNavigationEntryMatchLoadParams(load_params, entry); | |
564 } | |
565 | |
566 // Tests what happens when the same page is loaded again. Should not create a | |
567 // new session history entry. This is what happens when you press enter in the | |
568 // URL bar to reload: a pending entry is created and then it is discarded when | |
569 // the load commits (because WebCore didn't actually make a new entry). | |
570 TEST_F(NavigationControllerTest, LoadURL_SamePage) { | |
571 NavigationControllerImpl& controller = controller_impl(); | |
572 TestNotificationTracker notifications; | |
573 RegisterForAllNavNotifications(¬ifications, &controller); | |
574 | |
575 const GURL url1("http://foo1"); | |
576 | |
577 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
578 EXPECT_EQ(0U, notifications.size()); | |
579 test_rvh()->SendNavigate(0, url1); | |
580 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
581 navigation_entry_committed_counter_ = 0; | |
582 | |
583 ASSERT_TRUE(controller.GetVisibleEntry()); | |
584 const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp(); | |
585 EXPECT_FALSE(timestamp.is_null()); | |
586 | |
587 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
588 EXPECT_EQ(0U, notifications.size()); | |
589 test_rvh()->SendNavigate(0, url1); | |
590 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
591 navigation_entry_committed_counter_ = 0; | |
592 | |
593 // We should not have produced a new session history entry. | |
594 EXPECT_EQ(controller.GetEntryCount(), 1); | |
595 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
596 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
597 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
598 EXPECT_FALSE(controller.GetPendingEntry()); | |
599 ASSERT_TRUE(controller.GetVisibleEntry()); | |
600 EXPECT_FALSE(controller.CanGoBack()); | |
601 EXPECT_FALSE(controller.CanGoForward()); | |
602 | |
603 // The timestamp should have been updated. | |
604 // | |
605 // TODO(akalin): Change this EXPECT_GE (and other similar ones) to | |
606 // EXPECT_GT once we guarantee that timestamps are unique. | |
607 EXPECT_GE(controller.GetVisibleEntry()->GetTimestamp(), timestamp); | |
608 } | |
609 | |
610 // Tests loading a URL but discarding it before the load commits. | |
611 TEST_F(NavigationControllerTest, LoadURL_Discarded) { | |
612 NavigationControllerImpl& controller = controller_impl(); | |
613 TestNotificationTracker notifications; | |
614 RegisterForAllNavNotifications(¬ifications, &controller); | |
615 | |
616 const GURL url1("http://foo1"); | |
617 const GURL url2("http://foo2"); | |
618 | |
619 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
620 EXPECT_EQ(0U, notifications.size()); | |
621 test_rvh()->SendNavigate(0, url1); | |
622 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
623 navigation_entry_committed_counter_ = 0; | |
624 | |
625 ASSERT_TRUE(controller.GetVisibleEntry()); | |
626 const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp(); | |
627 EXPECT_FALSE(timestamp.is_null()); | |
628 | |
629 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
630 controller.DiscardNonCommittedEntries(); | |
631 EXPECT_EQ(0U, notifications.size()); | |
632 | |
633 // Should not have produced a new session history entry. | |
634 EXPECT_EQ(controller.GetEntryCount(), 1); | |
635 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
636 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
637 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
638 EXPECT_FALSE(controller.GetPendingEntry()); | |
639 ASSERT_TRUE(controller.GetVisibleEntry()); | |
640 EXPECT_FALSE(controller.CanGoBack()); | |
641 EXPECT_FALSE(controller.CanGoForward()); | |
642 | |
643 // Timestamp should not have changed. | |
644 EXPECT_EQ(timestamp, controller.GetVisibleEntry()->GetTimestamp()); | |
645 } | |
646 | |
647 // Tests navigations that come in unrequested. This happens when the user | |
648 // navigates from the web page, and here we test that there is no pending entry. | |
649 TEST_F(NavigationControllerTest, LoadURL_NoPending) { | |
650 NavigationControllerImpl& controller = controller_impl(); | |
651 TestNotificationTracker notifications; | |
652 RegisterForAllNavNotifications(¬ifications, &controller); | |
653 | |
654 // First make an existing committed entry. | |
655 const GURL kExistingURL1("http://eh"); | |
656 controller.LoadURL( | |
657 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
658 test_rvh()->SendNavigate(0, kExistingURL1); | |
659 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
660 navigation_entry_committed_counter_ = 0; | |
661 | |
662 // Do a new navigation without making a pending one. | |
663 const GURL kNewURL("http://see"); | |
664 test_rvh()->SendNavigate(99, kNewURL); | |
665 | |
666 // There should no longer be any pending entry, and the third navigation we | |
667 // just made should be committed. | |
668 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
669 navigation_entry_committed_counter_ = 0; | |
670 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
671 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); | |
672 EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL()); | |
673 } | |
674 | |
675 // Tests navigating to a new URL when there is a new pending navigation that is | |
676 // not the one that just loaded. This will happen if the user types in a URL to | |
677 // somewhere slow, and then navigates the current page before the typed URL | |
678 // commits. | |
679 TEST_F(NavigationControllerTest, LoadURL_NewPending) { | |
680 NavigationControllerImpl& controller = controller_impl(); | |
681 TestNotificationTracker notifications; | |
682 RegisterForAllNavNotifications(¬ifications, &controller); | |
683 | |
684 // First make an existing committed entry. | |
685 const GURL kExistingURL1("http://eh"); | |
686 controller.LoadURL( | |
687 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
688 test_rvh()->SendNavigate(0, kExistingURL1); | |
689 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
690 navigation_entry_committed_counter_ = 0; | |
691 | |
692 // Make a pending entry to somewhere new. | |
693 const GURL kExistingURL2("http://bee"); | |
694 controller.LoadURL( | |
695 kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
696 EXPECT_EQ(0U, notifications.size()); | |
697 | |
698 // After the beforeunload but before it commits, do a new navigation. | |
699 test_rvh()->SendShouldCloseACK(true); | |
700 const GURL kNewURL("http://see"); | |
701 static_cast<TestRenderViewHost*>( | |
702 contents()->GetPendingRenderViewHost())->SendNavigate(3, kNewURL); | |
703 | |
704 // There should no longer be any pending entry, and the third navigation we | |
705 // just made should be committed. | |
706 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
707 navigation_entry_committed_counter_ = 0; | |
708 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
709 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); | |
710 EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL()); | |
711 } | |
712 | |
713 // Tests navigating to a new URL when there is a pending back/forward | |
714 // navigation. This will happen if the user hits back, but before that commits, | |
715 // they navigate somewhere new. | |
716 TEST_F(NavigationControllerTest, LoadURL_ExistingPending) { | |
717 NavigationControllerImpl& controller = controller_impl(); | |
718 TestNotificationTracker notifications; | |
719 RegisterForAllNavNotifications(¬ifications, &controller); | |
720 | |
721 // First make some history. | |
722 const GURL kExistingURL1("http://foo/eh"); | |
723 controller.LoadURL( | |
724 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
725 test_rvh()->SendNavigate(0, kExistingURL1); | |
726 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
727 navigation_entry_committed_counter_ = 0; | |
728 | |
729 const GURL kExistingURL2("http://foo/bee"); | |
730 controller.LoadURL( | |
731 kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
732 test_rvh()->SendNavigate(1, kExistingURL2); | |
733 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
734 navigation_entry_committed_counter_ = 0; | |
735 | |
736 // Now make a pending back/forward navigation. The zeroth entry should be | |
737 // pending. | |
738 controller.GoBack(); | |
739 EXPECT_EQ(0U, notifications.size()); | |
740 EXPECT_EQ(0, controller.GetPendingEntryIndex()); | |
741 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); | |
742 | |
743 // Before that commits, do a new navigation. | |
744 const GURL kNewURL("http://foo/see"); | |
745 LoadCommittedDetails details; | |
746 test_rvh()->SendNavigate(3, kNewURL); | |
747 | |
748 // There should no longer be any pending entry, and the third navigation we | |
749 // just made should be committed. | |
750 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
751 navigation_entry_committed_counter_ = 0; | |
752 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
753 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex()); | |
754 EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL()); | |
755 } | |
756 | |
757 // Tests navigating to a new URL when there is a pending back/forward | |
758 // navigation to a cross-process, privileged URL. This will happen if the user | |
759 // hits back, but before that commits, they navigate somewhere new. | |
760 TEST_F(NavigationControllerTest, LoadURL_PrivilegedPending) { | |
761 NavigationControllerImpl& controller = controller_impl(); | |
762 TestNotificationTracker notifications; | |
763 RegisterForAllNavNotifications(¬ifications, &controller); | |
764 | |
765 // First make some history, starting with a privileged URL. | |
766 const GURL kExistingURL1("http://privileged"); | |
767 controller.LoadURL( | |
768 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
769 // Pretend it has bindings so we can tell if we incorrectly copy it. | |
770 test_rvh()->AllowBindings(2); | |
771 test_rvh()->SendNavigate(0, kExistingURL1); | |
772 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
773 navigation_entry_committed_counter_ = 0; | |
774 | |
775 // Navigate cross-process to a second URL. | |
776 const GURL kExistingURL2("http://foo/eh"); | |
777 controller.LoadURL( | |
778 kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
779 test_rvh()->SendShouldCloseACK(true); | |
780 TestRenderViewHost* foo_rvh = static_cast<TestRenderViewHost*>( | |
781 contents()->GetPendingRenderViewHost()); | |
782 foo_rvh->SendNavigate(1, kExistingURL2); | |
783 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
784 navigation_entry_committed_counter_ = 0; | |
785 | |
786 // Now make a pending back/forward navigation to a privileged entry. | |
787 // The zeroth entry should be pending. | |
788 controller.GoBack(); | |
789 foo_rvh->SendShouldCloseACK(true); | |
790 EXPECT_EQ(0U, notifications.size()); | |
791 EXPECT_EQ(0, controller.GetPendingEntryIndex()); | |
792 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); | |
793 EXPECT_EQ(2, NavigationEntryImpl::FromNavigationEntry( | |
794 controller.GetPendingEntry())->bindings()); | |
795 | |
796 // Before that commits, do a new navigation. | |
797 const GURL kNewURL("http://foo/bee"); | |
798 LoadCommittedDetails details; | |
799 foo_rvh->SendNavigate(3, kNewURL); | |
800 | |
801 // There should no longer be any pending entry, and the third navigation we | |
802 // just made should be committed. | |
803 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
804 navigation_entry_committed_counter_ = 0; | |
805 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
806 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex()); | |
807 EXPECT_EQ(kNewURL, controller.GetVisibleEntry()->GetURL()); | |
808 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry( | |
809 controller.GetLastCommittedEntry())->bindings()); | |
810 } | |
811 | |
812 // Tests navigating to an existing URL when there is a pending new navigation. | |
813 // This will happen if the user enters a URL, but before that commits, the | |
814 // current page fires history.back(). | |
815 TEST_F(NavigationControllerTest, LoadURL_BackPreemptsPending) { | |
816 NavigationControllerImpl& controller = controller_impl(); | |
817 TestNotificationTracker notifications; | |
818 RegisterForAllNavNotifications(¬ifications, &controller); | |
819 | |
820 // First make some history. | |
821 const GURL kExistingURL1("http://foo/eh"); | |
822 controller.LoadURL( | |
823 kExistingURL1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
824 test_rvh()->SendNavigate(0, kExistingURL1); | |
825 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
826 navigation_entry_committed_counter_ = 0; | |
827 | |
828 const GURL kExistingURL2("http://foo/bee"); | |
829 controller.LoadURL( | |
830 kExistingURL2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
831 test_rvh()->SendNavigate(1, kExistingURL2); | |
832 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
833 navigation_entry_committed_counter_ = 0; | |
834 | |
835 // Now make a pending new navigation. | |
836 const GURL kNewURL("http://foo/see"); | |
837 controller.LoadURL( | |
838 kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
839 EXPECT_EQ(0U, notifications.size()); | |
840 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
841 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); | |
842 | |
843 // Before that commits, a back navigation from the renderer commits. | |
844 test_rvh()->SendNavigate(0, kExistingURL1); | |
845 | |
846 // There should no longer be any pending entry, and the back navigation we | |
847 // just made should be committed. | |
848 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
849 navigation_entry_committed_counter_ = 0; | |
850 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
851 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); | |
852 EXPECT_EQ(kExistingURL1, controller.GetVisibleEntry()->GetURL()); | |
853 } | |
854 | |
855 // Tests an ignored navigation when there is a pending new navigation. | |
856 // This will happen if the user enters a URL, but before that commits, the | |
857 // current blank page reloads. See http://crbug.com/77507. | |
858 TEST_F(NavigationControllerTest, LoadURL_IgnorePreemptsPending) { | |
859 NavigationControllerImpl& controller = controller_impl(); | |
860 TestNotificationTracker notifications; | |
861 RegisterForAllNavNotifications(¬ifications, &controller); | |
862 | |
863 // Set a WebContentsDelegate to listen for state changes. | |
864 scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate()); | |
865 EXPECT_FALSE(contents()->GetDelegate()); | |
866 contents()->SetDelegate(delegate.get()); | |
867 | |
868 // Without any navigations, the renderer starts at about:blank. | |
869 const GURL kExistingURL(kAboutBlankURL); | |
870 | |
871 // Now make a pending new navigation. | |
872 const GURL kNewURL("http://eh"); | |
873 controller.LoadURL( | |
874 kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
875 EXPECT_EQ(0U, notifications.size()); | |
876 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
877 EXPECT_TRUE(controller.GetPendingEntry()); | |
878 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex()); | |
879 EXPECT_EQ(1, delegate->navigation_state_change_count()); | |
880 | |
881 // Before that commits, a document.write and location.reload can cause the | |
882 // renderer to send a FrameNavigate with page_id -1. | |
883 test_rvh()->SendNavigate(-1, kExistingURL); | |
884 | |
885 // This should clear the pending entry and notify of a navigation state | |
886 // change, so that we do not keep displaying kNewURL. | |
887 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
888 EXPECT_FALSE(controller.GetPendingEntry()); | |
889 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex()); | |
890 EXPECT_EQ(2, delegate->navigation_state_change_count()); | |
891 | |
892 contents()->SetDelegate(NULL); | |
893 } | |
894 | |
895 // Tests that the pending entry state is correct after an abort. | |
896 // We do not want to clear the pending entry, so that the user doesn't | |
897 // lose a typed URL. (See http://crbug.com/9682.) | |
898 TEST_F(NavigationControllerTest, LoadURL_AbortDoesntCancelPending) { | |
899 NavigationControllerImpl& controller = controller_impl(); | |
900 TestNotificationTracker notifications; | |
901 RegisterForAllNavNotifications(¬ifications, &controller); | |
902 | |
903 // Set a WebContentsDelegate to listen for state changes. | |
904 scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate()); | |
905 EXPECT_FALSE(contents()->GetDelegate()); | |
906 contents()->SetDelegate(delegate.get()); | |
907 | |
908 // Start with a pending new navigation. | |
909 const GURL kNewURL("http://eh"); | |
910 controller.LoadURL( | |
911 kNewURL, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
912 EXPECT_EQ(0U, notifications.size()); | |
913 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
914 EXPECT_TRUE(controller.GetPendingEntry()); | |
915 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex()); | |
916 EXPECT_EQ(1, delegate->navigation_state_change_count()); | |
917 | |
918 // It may abort before committing, if it's a download or due to a stop or | |
919 // a new navigation from the user. | |
920 ViewHostMsg_DidFailProvisionalLoadWithError_Params params; | |
921 params.frame_id = 1; | |
922 params.is_main_frame = true; | |
923 params.error_code = net::ERR_ABORTED; | |
924 params.error_description = string16(); | |
925 params.url = kNewURL; | |
926 params.showing_repost_interstitial = false; | |
927 test_rvh()->OnMessageReceived( | |
928 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id | |
929 params)); | |
930 | |
931 // This should not clear the pending entry or notify of a navigation state | |
932 // change, so that we keep displaying kNewURL (until the user clears it). | |
933 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
934 EXPECT_TRUE(controller.GetPendingEntry()); | |
935 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex()); | |
936 EXPECT_EQ(1, delegate->navigation_state_change_count()); | |
937 NavigationEntry* pending_entry = controller.GetPendingEntry(); | |
938 | |
939 // Ensure that a reload keeps the same pending entry. | |
940 controller.Reload(true); | |
941 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
942 EXPECT_TRUE(controller.GetPendingEntry()); | |
943 EXPECT_EQ(pending_entry, controller.GetPendingEntry()); | |
944 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex()); | |
945 | |
946 contents()->SetDelegate(NULL); | |
947 } | |
948 | |
949 // Tests that the pending URL is not visible during a renderer-initiated | |
950 // redirect and abort. See http://crbug.com/83031. | |
951 TEST_F(NavigationControllerTest, LoadURL_RedirectAbortDoesntShowPendingURL) { | |
952 NavigationControllerImpl& controller = controller_impl(); | |
953 TestNotificationTracker notifications; | |
954 RegisterForAllNavNotifications(¬ifications, &controller); | |
955 | |
956 // First make an existing committed entry. | |
957 const GURL kExistingURL("http://foo/eh"); | |
958 controller.LoadURL(kExistingURL, content::Referrer(), | |
959 content::PAGE_TRANSITION_TYPED, std::string()); | |
960 test_rvh()->SendNavigate(0, kExistingURL); | |
961 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
962 navigation_entry_committed_counter_ = 0; | |
963 | |
964 // Set a WebContentsDelegate to listen for state changes. | |
965 scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate()); | |
966 EXPECT_FALSE(contents()->GetDelegate()); | |
967 contents()->SetDelegate(delegate.get()); | |
968 | |
969 // Now make a pending new navigation, initiated by the renderer. | |
970 const GURL kNewURL("http://foo/bee"); | |
971 NavigationController::LoadURLParams load_url_params(kNewURL); | |
972 load_url_params.transition_type = PAGE_TRANSITION_TYPED; | |
973 load_url_params.is_renderer_initiated = true; | |
974 controller.LoadURLWithParams(load_url_params); | |
975 EXPECT_EQ(0U, notifications.size()); | |
976 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
977 EXPECT_TRUE(controller.GetPendingEntry()); | |
978 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); | |
979 EXPECT_EQ(0, delegate->navigation_state_change_count()); | |
980 | |
981 // The visible entry should be the last committed URL, not the pending one. | |
982 EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL()); | |
983 | |
984 // Now the navigation redirects. | |
985 const GURL kRedirectURL("http://foo/see"); | |
986 test_rvh()->OnMessageReceived( | |
987 ViewHostMsg_DidRedirectProvisionalLoad(0, // routing_id | |
988 -1, // pending page_id | |
989 kNewURL, // old url | |
990 kRedirectURL)); // new url | |
991 | |
992 // We don't want to change the NavigationEntry's url, in case it cancels. | |
993 // Prevents regression of http://crbug.com/77786. | |
994 EXPECT_EQ(kNewURL, controller.GetPendingEntry()->GetURL()); | |
995 | |
996 // It may abort before committing, if it's a download or due to a stop or | |
997 // a new navigation from the user. | |
998 ViewHostMsg_DidFailProvisionalLoadWithError_Params params; | |
999 params.frame_id = 1; | |
1000 params.is_main_frame = true; | |
1001 params.error_code = net::ERR_ABORTED; | |
1002 params.error_description = string16(); | |
1003 params.url = kRedirectURL; | |
1004 params.showing_repost_interstitial = false; | |
1005 test_rvh()->OnMessageReceived( | |
1006 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id | |
1007 params)); | |
1008 | |
1009 // Because the pending entry is renderer initiated and not visible, we | |
1010 // clear it when it fails. | |
1011 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
1012 EXPECT_FALSE(controller.GetPendingEntry()); | |
1013 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); | |
1014 EXPECT_EQ(0, delegate->navigation_state_change_count()); | |
1015 | |
1016 // The visible entry should be the last committed URL, not the pending one, | |
1017 // so that no spoof is possible. | |
1018 EXPECT_EQ(kExistingURL, controller.GetVisibleEntry()->GetURL()); | |
1019 | |
1020 contents()->SetDelegate(NULL); | |
1021 } | |
1022 | |
1023 // Ensure that NavigationEntries track which bindings their RenderViewHost had | |
1024 // at the time they committed. http://crbug.com/173672. | |
1025 TEST_F(NavigationControllerTest, LoadURL_WithBindings) { | |
1026 NavigationControllerImpl& controller = controller_impl(); | |
1027 TestNotificationTracker notifications; | |
1028 RegisterForAllNavNotifications(¬ifications, &controller); | |
1029 | |
1030 const GURL url1("http://foo1"); | |
1031 const GURL url2("http://foo2"); | |
1032 | |
1033 // Navigate to a first, unprivileged URL. | |
1034 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1035 EXPECT_EQ(NavigationEntryImpl::kInvalidBindings, | |
1036 NavigationEntryImpl::FromNavigationEntry( | |
1037 controller.GetPendingEntry())->bindings()); | |
1038 | |
1039 // Commit. | |
1040 TestRenderViewHost* orig_rvh = static_cast<TestRenderViewHost*>(test_rvh()); | |
1041 orig_rvh->SendNavigate(0, url1); | |
1042 EXPECT_EQ(controller.GetEntryCount(), 1); | |
1043 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); | |
1044 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry( | |
1045 controller.GetLastCommittedEntry())->bindings()); | |
1046 | |
1047 // Manually increase the number of active views in the SiteInstance | |
1048 // that orig_rvh belongs to, to prevent it from being destroyed when | |
1049 // it gets swapped out, so that we can reuse orig_rvh when the | |
1050 // controller goes back. | |
1051 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())-> | |
1052 increment_active_view_count(); | |
1053 | |
1054 // Navigate to a second URL, simulate the beforeunload ack for the cross-site | |
1055 // transition, and set bindings on the pending RenderViewHost to simulate a | |
1056 // privileged url. | |
1057 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1058 orig_rvh->SendShouldCloseACK(true); | |
1059 contents()->GetPendingRenderViewHost()->AllowBindings(1); | |
1060 static_cast<TestRenderViewHost*>( | |
1061 contents()->GetPendingRenderViewHost())->SendNavigate(1, url2); | |
1062 | |
1063 // The second load should be committed, and bindings should be remembered. | |
1064 EXPECT_EQ(controller.GetEntryCount(), 2); | |
1065 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); | |
1066 EXPECT_TRUE(controller.CanGoBack()); | |
1067 EXPECT_EQ(1, NavigationEntryImpl::FromNavigationEntry( | |
1068 controller.GetLastCommittedEntry())->bindings()); | |
1069 | |
1070 // Going back, the first entry should still appear unprivileged. | |
1071 controller.GoBack(); | |
1072 orig_rvh->SendNavigate(0, url1); | |
1073 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); | |
1074 EXPECT_EQ(0, NavigationEntryImpl::FromNavigationEntry( | |
1075 controller.GetLastCommittedEntry())->bindings()); | |
1076 } | |
1077 | |
1078 TEST_F(NavigationControllerTest, Reload) { | |
1079 NavigationControllerImpl& controller = controller_impl(); | |
1080 TestNotificationTracker notifications; | |
1081 RegisterForAllNavNotifications(¬ifications, &controller); | |
1082 | |
1083 const GURL url1("http://foo1"); | |
1084 | |
1085 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1086 EXPECT_EQ(0U, notifications.size()); | |
1087 test_rvh()->SendNavigate(0, url1); | |
1088 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1089 navigation_entry_committed_counter_ = 0; | |
1090 ASSERT_TRUE(controller.GetVisibleEntry()); | |
1091 controller.GetVisibleEntry()->SetTitle(ASCIIToUTF16("Title")); | |
1092 controller.Reload(true); | |
1093 EXPECT_EQ(0U, notifications.size()); | |
1094 | |
1095 const base::Time timestamp = controller.GetVisibleEntry()->GetTimestamp(); | |
1096 EXPECT_FALSE(timestamp.is_null()); | |
1097 | |
1098 // The reload is pending. | |
1099 EXPECT_EQ(controller.GetEntryCount(), 1); | |
1100 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
1101 EXPECT_EQ(controller.GetPendingEntryIndex(), 0); | |
1102 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1103 EXPECT_TRUE(controller.GetPendingEntry()); | |
1104 EXPECT_FALSE(controller.CanGoBack()); | |
1105 EXPECT_FALSE(controller.CanGoForward()); | |
1106 // Make sure the title has been cleared (will be redrawn just after reload). | |
1107 // Avoids a stale cached title when the new page being reloaded has no title. | |
1108 // See http://crbug.com/96041. | |
1109 EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty()); | |
1110 | |
1111 test_rvh()->SendNavigate(0, url1); | |
1112 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1113 navigation_entry_committed_counter_ = 0; | |
1114 | |
1115 // Now the reload is committed. | |
1116 EXPECT_EQ(controller.GetEntryCount(), 1); | |
1117 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
1118 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1119 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1120 EXPECT_FALSE(controller.GetPendingEntry()); | |
1121 EXPECT_FALSE(controller.CanGoBack()); | |
1122 EXPECT_FALSE(controller.CanGoForward()); | |
1123 | |
1124 // The timestamp should have been updated. | |
1125 ASSERT_TRUE(controller.GetVisibleEntry()); | |
1126 EXPECT_GE(controller.GetVisibleEntry()->GetTimestamp(), timestamp); | |
1127 } | |
1128 | |
1129 // Tests what happens when a reload navigation produces a new page. | |
1130 TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) { | |
1131 NavigationControllerImpl& controller = controller_impl(); | |
1132 TestNotificationTracker notifications; | |
1133 RegisterForAllNavNotifications(¬ifications, &controller); | |
1134 | |
1135 const GURL url1("http://foo1"); | |
1136 const GURL url2("http://foo2"); | |
1137 | |
1138 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1139 test_rvh()->SendNavigate(0, url1); | |
1140 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1141 navigation_entry_committed_counter_ = 0; | |
1142 | |
1143 controller.Reload(true); | |
1144 EXPECT_EQ(0U, notifications.size()); | |
1145 | |
1146 test_rvh()->SendNavigate(1, url2); | |
1147 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1148 navigation_entry_committed_counter_ = 0; | |
1149 | |
1150 // Now the reload is committed. | |
1151 EXPECT_EQ(controller.GetEntryCount(), 2); | |
1152 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1); | |
1153 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1154 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1155 EXPECT_FALSE(controller.GetPendingEntry()); | |
1156 EXPECT_TRUE(controller.CanGoBack()); | |
1157 EXPECT_FALSE(controller.CanGoForward()); | |
1158 } | |
1159 | |
1160 #if !defined(OS_ANDROID) // http://crbug.com/157428 | |
1161 TEST_F(NavigationControllerTest, ReloadOriginalRequestURL) { | |
1162 NavigationControllerImpl& controller = controller_impl(); | |
1163 TestNotificationTracker notifications; | |
1164 RegisterForAllNavNotifications(¬ifications, &controller); | |
1165 | |
1166 const GURL original_url("http://foo1"); | |
1167 const GURL final_url("http://foo2"); | |
1168 | |
1169 // Load up the original URL, but get redirected. | |
1170 controller.LoadURL( | |
1171 original_url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1172 EXPECT_EQ(0U, notifications.size()); | |
1173 test_rvh()->SendNavigateWithOriginalRequestURL(0, final_url, original_url); | |
1174 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1175 navigation_entry_committed_counter_ = 0; | |
1176 | |
1177 // The NavigationEntry should save both the original URL and the final | |
1178 // redirected URL. | |
1179 EXPECT_EQ( | |
1180 original_url, controller.GetVisibleEntry()->GetOriginalRequestURL()); | |
1181 EXPECT_EQ(final_url, controller.GetVisibleEntry()->GetURL()); | |
1182 | |
1183 // Reload using the original URL. | |
1184 controller.GetVisibleEntry()->SetTitle(ASCIIToUTF16("Title")); | |
1185 controller.ReloadOriginalRequestURL(false); | |
1186 EXPECT_EQ(0U, notifications.size()); | |
1187 | |
1188 // The reload is pending. The request should point to the original URL. | |
1189 EXPECT_EQ(original_url, navigated_url()); | |
1190 EXPECT_EQ(controller.GetEntryCount(), 1); | |
1191 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
1192 EXPECT_EQ(controller.GetPendingEntryIndex(), 0); | |
1193 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1194 EXPECT_TRUE(controller.GetPendingEntry()); | |
1195 EXPECT_FALSE(controller.CanGoBack()); | |
1196 EXPECT_FALSE(controller.CanGoForward()); | |
1197 | |
1198 // Make sure the title has been cleared (will be redrawn just after reload). | |
1199 // Avoids a stale cached title when the new page being reloaded has no title. | |
1200 // See http://crbug.com/96041. | |
1201 EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty()); | |
1202 | |
1203 // Send that the navigation has proceeded; say it got redirected again. | |
1204 test_rvh()->SendNavigate(0, final_url); | |
1205 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1206 navigation_entry_committed_counter_ = 0; | |
1207 | |
1208 // Now the reload is committed. | |
1209 EXPECT_EQ(controller.GetEntryCount(), 1); | |
1210 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
1211 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1212 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1213 EXPECT_FALSE(controller.GetPendingEntry()); | |
1214 EXPECT_FALSE(controller.CanGoBack()); | |
1215 EXPECT_FALSE(controller.CanGoForward()); | |
1216 } | |
1217 | |
1218 #endif // !defined(OS_ANDROID) | |
1219 | |
1220 // Tests what happens when we navigate back successfully | |
1221 TEST_F(NavigationControllerTest, Back) { | |
1222 NavigationControllerImpl& controller = controller_impl(); | |
1223 TestNotificationTracker notifications; | |
1224 RegisterForAllNavNotifications(¬ifications, &controller); | |
1225 | |
1226 const GURL url1("http://foo1"); | |
1227 test_rvh()->SendNavigate(0, url1); | |
1228 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1229 navigation_entry_committed_counter_ = 0; | |
1230 | |
1231 const GURL url2("http://foo2"); | |
1232 test_rvh()->SendNavigate(1, url2); | |
1233 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1234 navigation_entry_committed_counter_ = 0; | |
1235 | |
1236 controller.GoBack(); | |
1237 EXPECT_EQ(0U, notifications.size()); | |
1238 | |
1239 // We should now have a pending navigation to go back. | |
1240 EXPECT_EQ(controller.GetEntryCount(), 2); | |
1241 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1); | |
1242 EXPECT_EQ(controller.GetPendingEntryIndex(), 0); | |
1243 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1244 EXPECT_TRUE(controller.GetPendingEntry()); | |
1245 EXPECT_FALSE(controller.CanGoBack()); | |
1246 EXPECT_FALSE(controller.CanGoToOffset(-1)); | |
1247 EXPECT_TRUE(controller.CanGoForward()); | |
1248 EXPECT_TRUE(controller.CanGoToOffset(1)); | |
1249 EXPECT_FALSE(controller.CanGoToOffset(2)); // Cannot go foward 2 steps. | |
1250 | |
1251 // Timestamp for entry 1 should be on or after that of entry 0. | |
1252 EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null()); | |
1253 EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(), | |
1254 controller.GetEntryAtIndex(0)->GetTimestamp()); | |
1255 | |
1256 test_rvh()->SendNavigate(0, url2); | |
1257 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1258 navigation_entry_committed_counter_ = 0; | |
1259 | |
1260 // The back navigation completed successfully. | |
1261 EXPECT_EQ(controller.GetEntryCount(), 2); | |
1262 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
1263 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1264 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1265 EXPECT_FALSE(controller.GetPendingEntry()); | |
1266 EXPECT_FALSE(controller.CanGoBack()); | |
1267 EXPECT_FALSE(controller.CanGoToOffset(-1)); | |
1268 EXPECT_TRUE(controller.CanGoForward()); | |
1269 EXPECT_TRUE(controller.CanGoToOffset(1)); | |
1270 EXPECT_FALSE(controller.CanGoToOffset(2)); // Cannot go foward 2 steps. | |
1271 | |
1272 // Timestamp for entry 0 should be on or after that of entry 1 | |
1273 // (since we went back to it). | |
1274 EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(), | |
1275 controller.GetEntryAtIndex(1)->GetTimestamp()); | |
1276 } | |
1277 | |
1278 // Tests what happens when a back navigation produces a new page. | |
1279 TEST_F(NavigationControllerTest, Back_GeneratesNewPage) { | |
1280 NavigationControllerImpl& controller = controller_impl(); | |
1281 TestNotificationTracker notifications; | |
1282 RegisterForAllNavNotifications(¬ifications, &controller); | |
1283 | |
1284 const GURL url1("http://foo/1"); | |
1285 const GURL url2("http://foo/2"); | |
1286 const GURL url3("http://foo/3"); | |
1287 | |
1288 controller.LoadURL( | |
1289 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1290 test_rvh()->SendNavigate(0, url1); | |
1291 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1292 navigation_entry_committed_counter_ = 0; | |
1293 | |
1294 controller.LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1295 test_rvh()->SendNavigate(1, url2); | |
1296 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1297 navigation_entry_committed_counter_ = 0; | |
1298 | |
1299 controller.GoBack(); | |
1300 EXPECT_EQ(0U, notifications.size()); | |
1301 | |
1302 // We should now have a pending navigation to go back. | |
1303 EXPECT_EQ(controller.GetEntryCount(), 2); | |
1304 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1); | |
1305 EXPECT_EQ(controller.GetPendingEntryIndex(), 0); | |
1306 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1307 EXPECT_TRUE(controller.GetPendingEntry()); | |
1308 EXPECT_FALSE(controller.CanGoBack()); | |
1309 EXPECT_TRUE(controller.CanGoForward()); | |
1310 | |
1311 test_rvh()->SendNavigate(2, url3); | |
1312 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1313 navigation_entry_committed_counter_ = 0; | |
1314 | |
1315 // The back navigation resulted in a completely new navigation. | |
1316 // TODO(darin): perhaps this behavior will be confusing to users? | |
1317 EXPECT_EQ(controller.GetEntryCount(), 3); | |
1318 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2); | |
1319 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1320 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1321 EXPECT_FALSE(controller.GetPendingEntry()); | |
1322 EXPECT_TRUE(controller.CanGoBack()); | |
1323 EXPECT_FALSE(controller.CanGoForward()); | |
1324 } | |
1325 | |
1326 // Receives a back message when there is a new pending navigation entry. | |
1327 TEST_F(NavigationControllerTest, Back_NewPending) { | |
1328 NavigationControllerImpl& controller = controller_impl(); | |
1329 TestNotificationTracker notifications; | |
1330 RegisterForAllNavNotifications(¬ifications, &controller); | |
1331 | |
1332 const GURL kUrl1("http://foo1"); | |
1333 const GURL kUrl2("http://foo2"); | |
1334 const GURL kUrl3("http://foo3"); | |
1335 | |
1336 // First navigate two places so we have some back history. | |
1337 test_rvh()->SendNavigate(0, kUrl1); | |
1338 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1339 navigation_entry_committed_counter_ = 0; | |
1340 | |
1341 // controller.LoadURL(kUrl2, PAGE_TRANSITION_TYPED); | |
1342 test_rvh()->SendNavigate(1, kUrl2); | |
1343 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1344 navigation_entry_committed_counter_ = 0; | |
1345 | |
1346 // Now start a new pending navigation and go back before it commits. | |
1347 controller.LoadURL(kUrl3, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1348 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
1349 EXPECT_EQ(kUrl3, controller.GetPendingEntry()->GetURL()); | |
1350 controller.GoBack(); | |
1351 | |
1352 // The pending navigation should now be the "back" item and the new one | |
1353 // should be gone. | |
1354 EXPECT_EQ(0, controller.GetPendingEntryIndex()); | |
1355 EXPECT_EQ(kUrl1, controller.GetPendingEntry()->GetURL()); | |
1356 } | |
1357 | |
1358 // Receives a back message when there is a different renavigation already | |
1359 // pending. | |
1360 TEST_F(NavigationControllerTest, Back_OtherBackPending) { | |
1361 NavigationControllerImpl& controller = controller_impl(); | |
1362 const GURL kUrl1("http://foo/1"); | |
1363 const GURL kUrl2("http://foo/2"); | |
1364 const GURL kUrl3("http://foo/3"); | |
1365 | |
1366 // First navigate three places so we have some back history. | |
1367 test_rvh()->SendNavigate(0, kUrl1); | |
1368 test_rvh()->SendNavigate(1, kUrl2); | |
1369 test_rvh()->SendNavigate(2, kUrl3); | |
1370 | |
1371 // With nothing pending, say we get a navigation to the second entry. | |
1372 test_rvh()->SendNavigate(1, kUrl2); | |
1373 | |
1374 // We know all the entries have the same site instance, so we can just grab | |
1375 // a random one for looking up other entries. | |
1376 SiteInstance* site_instance = | |
1377 NavigationEntryImpl::FromNavigationEntry( | |
1378 controller.GetLastCommittedEntry())->site_instance(); | |
1379 | |
1380 // That second URL should be the last committed and it should have gotten the | |
1381 // new title. | |
1382 EXPECT_EQ(kUrl2, controller.GetEntryWithPageID(site_instance, 1)->GetURL()); | |
1383 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); | |
1384 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
1385 | |
1386 // Now go forward to the last item again and say it was committed. | |
1387 controller.GoForward(); | |
1388 test_rvh()->SendNavigate(2, kUrl3); | |
1389 | |
1390 // Now start going back one to the second page. It will be pending. | |
1391 controller.GoBack(); | |
1392 EXPECT_EQ(1, controller.GetPendingEntryIndex()); | |
1393 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex()); | |
1394 | |
1395 // Not synthesize a totally new back event to the first page. This will not | |
1396 // match the pending one. | |
1397 test_rvh()->SendNavigate(0, kUrl1); | |
1398 | |
1399 // The committed navigation should clear the pending entry. | |
1400 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
1401 | |
1402 // But the navigated entry should be the last committed. | |
1403 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); | |
1404 EXPECT_EQ(kUrl1, controller.GetLastCommittedEntry()->GetURL()); | |
1405 } | |
1406 | |
1407 // Tests what happens when we navigate forward successfully. | |
1408 TEST_F(NavigationControllerTest, Forward) { | |
1409 NavigationControllerImpl& controller = controller_impl(); | |
1410 TestNotificationTracker notifications; | |
1411 RegisterForAllNavNotifications(¬ifications, &controller); | |
1412 | |
1413 const GURL url1("http://foo1"); | |
1414 const GURL url2("http://foo2"); | |
1415 | |
1416 test_rvh()->SendNavigate(0, url1); | |
1417 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1418 navigation_entry_committed_counter_ = 0; | |
1419 | |
1420 test_rvh()->SendNavigate(1, url2); | |
1421 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1422 navigation_entry_committed_counter_ = 0; | |
1423 | |
1424 controller.GoBack(); | |
1425 test_rvh()->SendNavigate(0, url1); | |
1426 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1427 navigation_entry_committed_counter_ = 0; | |
1428 | |
1429 controller.GoForward(); | |
1430 | |
1431 // We should now have a pending navigation to go forward. | |
1432 EXPECT_EQ(controller.GetEntryCount(), 2); | |
1433 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
1434 EXPECT_EQ(controller.GetPendingEntryIndex(), 1); | |
1435 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1436 EXPECT_TRUE(controller.GetPendingEntry()); | |
1437 EXPECT_TRUE(controller.CanGoBack()); | |
1438 EXPECT_TRUE(controller.CanGoToOffset(-1)); | |
1439 EXPECT_FALSE(controller.CanGoToOffset(-2)); // Cannot go back 2 steps. | |
1440 EXPECT_FALSE(controller.CanGoForward()); | |
1441 EXPECT_FALSE(controller.CanGoToOffset(1)); | |
1442 | |
1443 // Timestamp for entry 0 should be on or after that of entry 1 | |
1444 // (since we went back to it). | |
1445 EXPECT_FALSE(controller.GetEntryAtIndex(0)->GetTimestamp().is_null()); | |
1446 EXPECT_GE(controller.GetEntryAtIndex(0)->GetTimestamp(), | |
1447 controller.GetEntryAtIndex(1)->GetTimestamp()); | |
1448 | |
1449 test_rvh()->SendNavigate(1, url2); | |
1450 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1451 navigation_entry_committed_counter_ = 0; | |
1452 | |
1453 // The forward navigation completed successfully. | |
1454 EXPECT_EQ(controller.GetEntryCount(), 2); | |
1455 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1); | |
1456 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1457 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1458 EXPECT_FALSE(controller.GetPendingEntry()); | |
1459 EXPECT_TRUE(controller.CanGoBack()); | |
1460 EXPECT_TRUE(controller.CanGoToOffset(-1)); | |
1461 EXPECT_FALSE(controller.CanGoToOffset(-2)); // Cannot go back 2 steps. | |
1462 EXPECT_FALSE(controller.CanGoForward()); | |
1463 EXPECT_FALSE(controller.CanGoToOffset(1)); | |
1464 | |
1465 // Timestamp for entry 1 should be on or after that of entry 0 | |
1466 // (since we went forward to it). | |
1467 EXPECT_GE(controller.GetEntryAtIndex(1)->GetTimestamp(), | |
1468 controller.GetEntryAtIndex(0)->GetTimestamp()); | |
1469 } | |
1470 | |
1471 // Tests what happens when a forward navigation produces a new page. | |
1472 TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) { | |
1473 NavigationControllerImpl& controller = controller_impl(); | |
1474 TestNotificationTracker notifications; | |
1475 RegisterForAllNavNotifications(¬ifications, &controller); | |
1476 | |
1477 const GURL url1("http://foo1"); | |
1478 const GURL url2("http://foo2"); | |
1479 const GURL url3("http://foo3"); | |
1480 | |
1481 test_rvh()->SendNavigate(0, url1); | |
1482 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1483 navigation_entry_committed_counter_ = 0; | |
1484 test_rvh()->SendNavigate(1, url2); | |
1485 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1486 navigation_entry_committed_counter_ = 0; | |
1487 | |
1488 controller.GoBack(); | |
1489 test_rvh()->SendNavigate(0, url1); | |
1490 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1491 navigation_entry_committed_counter_ = 0; | |
1492 | |
1493 controller.GoForward(); | |
1494 EXPECT_EQ(0U, notifications.size()); | |
1495 | |
1496 // Should now have a pending navigation to go forward. | |
1497 EXPECT_EQ(controller.GetEntryCount(), 2); | |
1498 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
1499 EXPECT_EQ(controller.GetPendingEntryIndex(), 1); | |
1500 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1501 EXPECT_TRUE(controller.GetPendingEntry()); | |
1502 EXPECT_TRUE(controller.CanGoBack()); | |
1503 EXPECT_FALSE(controller.CanGoForward()); | |
1504 | |
1505 test_rvh()->SendNavigate(2, url3); | |
1506 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1507 navigation_entry_committed_counter_ = 0; | |
1508 EXPECT_TRUE(notifications.Check1AndReset(NOTIFICATION_NAV_LIST_PRUNED)); | |
1509 | |
1510 EXPECT_EQ(controller.GetEntryCount(), 2); | |
1511 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1); | |
1512 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1513 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1514 EXPECT_FALSE(controller.GetPendingEntry()); | |
1515 EXPECT_TRUE(controller.CanGoBack()); | |
1516 EXPECT_FALSE(controller.CanGoForward()); | |
1517 } | |
1518 | |
1519 // Two consequent navigation for the same URL entered in should be considered | |
1520 // as SAME_PAGE navigation even when we are redirected to some other page. | |
1521 TEST_F(NavigationControllerTest, Redirect) { | |
1522 NavigationControllerImpl& controller = controller_impl(); | |
1523 TestNotificationTracker notifications; | |
1524 RegisterForAllNavNotifications(¬ifications, &controller); | |
1525 | |
1526 const GURL url1("http://foo1"); | |
1527 const GURL url2("http://foo2"); // Redirection target | |
1528 | |
1529 // First request | |
1530 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1531 | |
1532 EXPECT_EQ(0U, notifications.size()); | |
1533 test_rvh()->SendNavigate(0, url2); | |
1534 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1535 navigation_entry_committed_counter_ = 0; | |
1536 | |
1537 // Second request | |
1538 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1539 | |
1540 EXPECT_TRUE(controller.GetPendingEntry()); | |
1541 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1542 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL()); | |
1543 | |
1544 ViewHostMsg_FrameNavigate_Params params; | |
1545 params.page_id = 0; | |
1546 params.url = url2; | |
1547 params.transition = PAGE_TRANSITION_SERVER_REDIRECT; | |
1548 params.redirects.push_back(GURL("http://foo1")); | |
1549 params.redirects.push_back(GURL("http://foo2")); | |
1550 params.should_update_history = false; | |
1551 params.gesture = NavigationGestureAuto; | |
1552 params.is_post = false; | |
1553 params.page_state = PageState::CreateFromURL(url2); | |
1554 | |
1555 LoadCommittedDetails details; | |
1556 | |
1557 EXPECT_EQ(0U, notifications.size()); | |
1558 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
1559 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1560 navigation_entry_committed_counter_ = 0; | |
1561 | |
1562 EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE); | |
1563 EXPECT_EQ(controller.GetEntryCount(), 1); | |
1564 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
1565 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1566 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1567 EXPECT_FALSE(controller.GetPendingEntry()); | |
1568 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL()); | |
1569 | |
1570 EXPECT_FALSE(controller.CanGoBack()); | |
1571 EXPECT_FALSE(controller.CanGoForward()); | |
1572 } | |
1573 | |
1574 // Similar to Redirect above, but the first URL is requested by POST, | |
1575 // the second URL is requested by GET. NavigationEntry::has_post_data_ | |
1576 // must be cleared. http://crbug.com/21245 | |
1577 TEST_F(NavigationControllerTest, PostThenRedirect) { | |
1578 NavigationControllerImpl& controller = controller_impl(); | |
1579 TestNotificationTracker notifications; | |
1580 RegisterForAllNavNotifications(¬ifications, &controller); | |
1581 | |
1582 const GURL url1("http://foo1"); | |
1583 const GURL url2("http://foo2"); // Redirection target | |
1584 | |
1585 // First request as POST | |
1586 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1587 controller.GetVisibleEntry()->SetHasPostData(true); | |
1588 | |
1589 EXPECT_EQ(0U, notifications.size()); | |
1590 test_rvh()->SendNavigate(0, url2); | |
1591 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1592 navigation_entry_committed_counter_ = 0; | |
1593 | |
1594 // Second request | |
1595 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1596 | |
1597 EXPECT_TRUE(controller.GetPendingEntry()); | |
1598 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1599 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL()); | |
1600 | |
1601 ViewHostMsg_FrameNavigate_Params params; | |
1602 params.page_id = 0; | |
1603 params.url = url2; | |
1604 params.transition = PAGE_TRANSITION_SERVER_REDIRECT; | |
1605 params.redirects.push_back(GURL("http://foo1")); | |
1606 params.redirects.push_back(GURL("http://foo2")); | |
1607 params.should_update_history = false; | |
1608 params.gesture = NavigationGestureAuto; | |
1609 params.is_post = false; | |
1610 params.page_state = PageState::CreateFromURL(url2); | |
1611 | |
1612 LoadCommittedDetails details; | |
1613 | |
1614 EXPECT_EQ(0U, notifications.size()); | |
1615 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
1616 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1617 navigation_entry_committed_counter_ = 0; | |
1618 | |
1619 EXPECT_TRUE(details.type == NAVIGATION_TYPE_SAME_PAGE); | |
1620 EXPECT_EQ(controller.GetEntryCount(), 1); | |
1621 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
1622 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1623 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1624 EXPECT_FALSE(controller.GetPendingEntry()); | |
1625 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL()); | |
1626 EXPECT_FALSE(controller.GetVisibleEntry()->GetHasPostData()); | |
1627 | |
1628 EXPECT_FALSE(controller.CanGoBack()); | |
1629 EXPECT_FALSE(controller.CanGoForward()); | |
1630 } | |
1631 | |
1632 // A redirect right off the bat should be a NEW_PAGE. | |
1633 TEST_F(NavigationControllerTest, ImmediateRedirect) { | |
1634 NavigationControllerImpl& controller = controller_impl(); | |
1635 TestNotificationTracker notifications; | |
1636 RegisterForAllNavNotifications(¬ifications, &controller); | |
1637 | |
1638 const GURL url1("http://foo1"); | |
1639 const GURL url2("http://foo2"); // Redirection target | |
1640 | |
1641 // First request | |
1642 controller.LoadURL(url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
1643 | |
1644 EXPECT_TRUE(controller.GetPendingEntry()); | |
1645 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1646 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL()); | |
1647 | |
1648 ViewHostMsg_FrameNavigate_Params params; | |
1649 params.page_id = 0; | |
1650 params.url = url2; | |
1651 params.transition = PAGE_TRANSITION_SERVER_REDIRECT; | |
1652 params.redirects.push_back(GURL("http://foo1")); | |
1653 params.redirects.push_back(GURL("http://foo2")); | |
1654 params.should_update_history = false; | |
1655 params.gesture = NavigationGestureAuto; | |
1656 params.is_post = false; | |
1657 params.page_state = PageState::CreateFromURL(url2); | |
1658 | |
1659 LoadCommittedDetails details; | |
1660 | |
1661 EXPECT_EQ(0U, notifications.size()); | |
1662 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
1663 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1664 navigation_entry_committed_counter_ = 0; | |
1665 | |
1666 EXPECT_TRUE(details.type == NAVIGATION_TYPE_NEW_PAGE); | |
1667 EXPECT_EQ(controller.GetEntryCount(), 1); | |
1668 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
1669 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1670 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1671 EXPECT_FALSE(controller.GetPendingEntry()); | |
1672 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL()); | |
1673 | |
1674 EXPECT_FALSE(controller.CanGoBack()); | |
1675 EXPECT_FALSE(controller.CanGoForward()); | |
1676 } | |
1677 | |
1678 // Tests navigation via link click within a subframe. A new navigation entry | |
1679 // should be created. | |
1680 TEST_F(NavigationControllerTest, NewSubframe) { | |
1681 NavigationControllerImpl& controller = controller_impl(); | |
1682 TestNotificationTracker notifications; | |
1683 RegisterForAllNavNotifications(¬ifications, &controller); | |
1684 | |
1685 const GURL url1("http://foo1"); | |
1686 test_rvh()->SendNavigate(0, url1); | |
1687 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1688 navigation_entry_committed_counter_ = 0; | |
1689 | |
1690 const GURL url2("http://foo2"); | |
1691 ViewHostMsg_FrameNavigate_Params params; | |
1692 params.page_id = 1; | |
1693 params.url = url2; | |
1694 params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME; | |
1695 params.should_update_history = false; | |
1696 params.gesture = NavigationGestureUser; | |
1697 params.is_post = false; | |
1698 params.page_state = PageState::CreateFromURL(url2); | |
1699 | |
1700 LoadCommittedDetails details; | |
1701 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
1702 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1703 navigation_entry_committed_counter_ = 0; | |
1704 EXPECT_EQ(url1, details.previous_url); | |
1705 EXPECT_FALSE(details.is_in_page); | |
1706 EXPECT_FALSE(details.is_main_frame); | |
1707 | |
1708 // The new entry should be appended. | |
1709 EXPECT_EQ(2, controller.GetEntryCount()); | |
1710 | |
1711 // New entry should refer to the new page, but the old URL (entries only | |
1712 // reflect the toplevel URL). | |
1713 EXPECT_EQ(url1, details.entry->GetURL()); | |
1714 EXPECT_EQ(params.page_id, details.entry->GetPageID()); | |
1715 } | |
1716 | |
1717 // Some pages create a popup, then write an iframe into it. This causes a | |
1718 // subframe navigation without having any committed entry. Such navigations | |
1719 // just get thrown on the ground, but we shouldn't crash. | |
1720 TEST_F(NavigationControllerTest, SubframeOnEmptyPage) { | |
1721 NavigationControllerImpl& controller = controller_impl(); | |
1722 TestNotificationTracker notifications; | |
1723 RegisterForAllNavNotifications(¬ifications, &controller); | |
1724 | |
1725 // Navigation controller currently has no entries. | |
1726 const GURL url("http://foo2"); | |
1727 ViewHostMsg_FrameNavigate_Params params; | |
1728 params.page_id = 1; | |
1729 params.url = url; | |
1730 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME; | |
1731 params.should_update_history = false; | |
1732 params.gesture = NavigationGestureAuto; | |
1733 params.is_post = false; | |
1734 params.page_state = PageState::CreateFromURL(url); | |
1735 | |
1736 LoadCommittedDetails details; | |
1737 EXPECT_FALSE(controller.RendererDidNavigate(params, &details)); | |
1738 EXPECT_EQ(0U, notifications.size()); | |
1739 } | |
1740 | |
1741 // Auto subframes are ones the page loads automatically like ads. They should | |
1742 // not create new navigation entries. | |
1743 TEST_F(NavigationControllerTest, AutoSubframe) { | |
1744 NavigationControllerImpl& controller = controller_impl(); | |
1745 TestNotificationTracker notifications; | |
1746 RegisterForAllNavNotifications(¬ifications, &controller); | |
1747 | |
1748 const GURL url1("http://foo1"); | |
1749 test_rvh()->SendNavigate(0, url1); | |
1750 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1751 navigation_entry_committed_counter_ = 0; | |
1752 | |
1753 const GURL url2("http://foo2"); | |
1754 ViewHostMsg_FrameNavigate_Params params; | |
1755 params.page_id = 0; | |
1756 params.url = url2; | |
1757 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME; | |
1758 params.should_update_history = false; | |
1759 params.gesture = NavigationGestureUser; | |
1760 params.is_post = false; | |
1761 params.page_state = PageState::CreateFromURL(url2); | |
1762 | |
1763 // Navigating should do nothing. | |
1764 LoadCommittedDetails details; | |
1765 EXPECT_FALSE(controller.RendererDidNavigate(params, &details)); | |
1766 EXPECT_EQ(0U, notifications.size()); | |
1767 | |
1768 // There should still be only one entry. | |
1769 EXPECT_EQ(1, controller.GetEntryCount()); | |
1770 } | |
1771 | |
1772 // Tests navigation and then going back to a subframe navigation. | |
1773 TEST_F(NavigationControllerTest, BackSubframe) { | |
1774 NavigationControllerImpl& controller = controller_impl(); | |
1775 TestNotificationTracker notifications; | |
1776 RegisterForAllNavNotifications(¬ifications, &controller); | |
1777 | |
1778 // Main page. | |
1779 const GURL url1("http://foo1"); | |
1780 test_rvh()->SendNavigate(0, url1); | |
1781 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1782 navigation_entry_committed_counter_ = 0; | |
1783 | |
1784 // First manual subframe navigation. | |
1785 const GURL url2("http://foo2"); | |
1786 ViewHostMsg_FrameNavigate_Params params; | |
1787 params.page_id = 1; | |
1788 params.url = url2; | |
1789 params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME; | |
1790 params.should_update_history = false; | |
1791 params.gesture = NavigationGestureUser; | |
1792 params.is_post = false; | |
1793 params.page_state = PageState::CreateFromURL(url2); | |
1794 | |
1795 // This should generate a new entry. | |
1796 LoadCommittedDetails details; | |
1797 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
1798 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1799 navigation_entry_committed_counter_ = 0; | |
1800 EXPECT_EQ(2, controller.GetEntryCount()); | |
1801 | |
1802 // Second manual subframe navigation should also make a new entry. | |
1803 const GURL url3("http://foo3"); | |
1804 params.page_id = 2; | |
1805 params.url = url3; | |
1806 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
1807 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1808 navigation_entry_committed_counter_ = 0; | |
1809 EXPECT_EQ(3, controller.GetEntryCount()); | |
1810 EXPECT_EQ(2, controller.GetCurrentEntryIndex()); | |
1811 | |
1812 // Go back one. | |
1813 controller.GoBack(); | |
1814 params.url = url2; | |
1815 params.page_id = 1; | |
1816 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
1817 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1818 navigation_entry_committed_counter_ = 0; | |
1819 EXPECT_EQ(3, controller.GetEntryCount()); | |
1820 EXPECT_EQ(1, controller.GetCurrentEntryIndex()); | |
1821 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
1822 EXPECT_FALSE(controller.GetPendingEntry()); | |
1823 | |
1824 // Go back one more. | |
1825 controller.GoBack(); | |
1826 params.url = url1; | |
1827 params.page_id = 0; | |
1828 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
1829 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1830 navigation_entry_committed_counter_ = 0; | |
1831 EXPECT_EQ(3, controller.GetEntryCount()); | |
1832 EXPECT_EQ(0, controller.GetCurrentEntryIndex()); | |
1833 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
1834 EXPECT_FALSE(controller.GetPendingEntry()); | |
1835 } | |
1836 | |
1837 TEST_F(NavigationControllerTest, LinkClick) { | |
1838 NavigationControllerImpl& controller = controller_impl(); | |
1839 TestNotificationTracker notifications; | |
1840 RegisterForAllNavNotifications(¬ifications, &controller); | |
1841 | |
1842 const GURL url1("http://foo1"); | |
1843 const GURL url2("http://foo2"); | |
1844 | |
1845 test_rvh()->SendNavigate(0, url1); | |
1846 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1847 navigation_entry_committed_counter_ = 0; | |
1848 | |
1849 test_rvh()->SendNavigate(1, url2); | |
1850 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1851 navigation_entry_committed_counter_ = 0; | |
1852 | |
1853 // Should not have produced a new session history entry. | |
1854 EXPECT_EQ(controller.GetEntryCount(), 2); | |
1855 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1); | |
1856 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
1857 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
1858 EXPECT_FALSE(controller.GetPendingEntry()); | |
1859 EXPECT_TRUE(controller.CanGoBack()); | |
1860 EXPECT_FALSE(controller.CanGoForward()); | |
1861 } | |
1862 | |
1863 TEST_F(NavigationControllerTest, InPage) { | |
1864 NavigationControllerImpl& controller = controller_impl(); | |
1865 TestNotificationTracker notifications; | |
1866 RegisterForAllNavNotifications(¬ifications, &controller); | |
1867 | |
1868 // Main page. | |
1869 const GURL url1("http://foo"); | |
1870 test_rvh()->SendNavigate(0, url1); | |
1871 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1872 navigation_entry_committed_counter_ = 0; | |
1873 | |
1874 // Ensure main page navigation to same url respects the was_within_same_page | |
1875 // hint provided in the params. | |
1876 ViewHostMsg_FrameNavigate_Params self_params; | |
1877 self_params.page_id = 0; | |
1878 self_params.url = url1; | |
1879 self_params.transition = PAGE_TRANSITION_LINK; | |
1880 self_params.should_update_history = false; | |
1881 self_params.gesture = NavigationGestureUser; | |
1882 self_params.is_post = false; | |
1883 self_params.page_state = PageState::CreateFromURL(url1); | |
1884 self_params.was_within_same_page = true; | |
1885 | |
1886 LoadCommittedDetails details; | |
1887 EXPECT_TRUE(controller.RendererDidNavigate(self_params, &details)); | |
1888 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1889 navigation_entry_committed_counter_ = 0; | |
1890 EXPECT_TRUE(details.is_in_page); | |
1891 EXPECT_TRUE(details.did_replace_entry); | |
1892 EXPECT_EQ(1, controller.GetEntryCount()); | |
1893 | |
1894 // Fragment navigation to a new page_id. | |
1895 const GURL url2("http://foo#a"); | |
1896 ViewHostMsg_FrameNavigate_Params params; | |
1897 params.page_id = 1; | |
1898 params.url = url2; | |
1899 params.transition = PAGE_TRANSITION_LINK; | |
1900 params.should_update_history = false; | |
1901 params.gesture = NavigationGestureUser; | |
1902 params.is_post = false; | |
1903 params.page_state = PageState::CreateFromURL(url2); | |
1904 params.was_within_same_page = true; | |
1905 | |
1906 // This should generate a new entry. | |
1907 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
1908 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1909 navigation_entry_committed_counter_ = 0; | |
1910 EXPECT_TRUE(details.is_in_page); | |
1911 EXPECT_FALSE(details.did_replace_entry); | |
1912 EXPECT_EQ(2, controller.GetEntryCount()); | |
1913 | |
1914 // Go back one. | |
1915 ViewHostMsg_FrameNavigate_Params back_params(params); | |
1916 controller.GoBack(); | |
1917 back_params.url = url1; | |
1918 back_params.page_id = 0; | |
1919 EXPECT_TRUE(controller.RendererDidNavigate(back_params, &details)); | |
1920 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1921 navigation_entry_committed_counter_ = 0; | |
1922 EXPECT_TRUE(details.is_in_page); | |
1923 EXPECT_EQ(2, controller.GetEntryCount()); | |
1924 EXPECT_EQ(0, controller.GetCurrentEntryIndex()); | |
1925 EXPECT_EQ(back_params.url, controller.GetVisibleEntry()->GetURL()); | |
1926 | |
1927 // Go forward | |
1928 ViewHostMsg_FrameNavigate_Params forward_params(params); | |
1929 controller.GoForward(); | |
1930 forward_params.url = url2; | |
1931 forward_params.page_id = 1; | |
1932 EXPECT_TRUE(controller.RendererDidNavigate(forward_params, &details)); | |
1933 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1934 navigation_entry_committed_counter_ = 0; | |
1935 EXPECT_TRUE(details.is_in_page); | |
1936 EXPECT_EQ(2, controller.GetEntryCount()); | |
1937 EXPECT_EQ(1, controller.GetCurrentEntryIndex()); | |
1938 EXPECT_EQ(forward_params.url, | |
1939 controller.GetVisibleEntry()->GetURL()); | |
1940 | |
1941 // Now go back and forward again. This is to work around a bug where we would | |
1942 // compare the incoming URL with the last committed entry rather than the | |
1943 // one identified by an existing page ID. This would result in the second URL | |
1944 // losing the reference fragment when you navigate away from it and then back. | |
1945 controller.GoBack(); | |
1946 EXPECT_TRUE(controller.RendererDidNavigate(back_params, &details)); | |
1947 controller.GoForward(); | |
1948 EXPECT_TRUE(controller.RendererDidNavigate(forward_params, &details)); | |
1949 EXPECT_EQ(forward_params.url, | |
1950 controller.GetVisibleEntry()->GetURL()); | |
1951 | |
1952 // Finally, navigate to an unrelated URL to make sure in_page is not sticky. | |
1953 const GURL url3("http://bar"); | |
1954 params.page_id = 2; | |
1955 params.url = url3; | |
1956 navigation_entry_committed_counter_ = 0; | |
1957 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
1958 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1959 navigation_entry_committed_counter_ = 0; | |
1960 EXPECT_FALSE(details.is_in_page); | |
1961 EXPECT_EQ(3, controller.GetEntryCount()); | |
1962 EXPECT_EQ(2, controller.GetCurrentEntryIndex()); | |
1963 } | |
1964 | |
1965 TEST_F(NavigationControllerTest, InPage_Replace) { | |
1966 NavigationControllerImpl& controller = controller_impl(); | |
1967 TestNotificationTracker notifications; | |
1968 RegisterForAllNavNotifications(¬ifications, &controller); | |
1969 | |
1970 // Main page. | |
1971 const GURL url1("http://foo"); | |
1972 test_rvh()->SendNavigate(0, url1); | |
1973 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1974 navigation_entry_committed_counter_ = 0; | |
1975 | |
1976 // First navigation. | |
1977 const GURL url2("http://foo#a"); | |
1978 ViewHostMsg_FrameNavigate_Params params; | |
1979 params.page_id = 0; // Same page_id | |
1980 params.url = url2; | |
1981 params.transition = PAGE_TRANSITION_LINK; | |
1982 params.should_update_history = false; | |
1983 params.gesture = NavigationGestureUser; | |
1984 params.is_post = false; | |
1985 params.page_state = PageState::CreateFromURL(url2); | |
1986 | |
1987 // This should NOT generate a new entry, nor prune the list. | |
1988 LoadCommittedDetails details; | |
1989 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
1990 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
1991 navigation_entry_committed_counter_ = 0; | |
1992 EXPECT_TRUE(details.is_in_page); | |
1993 EXPECT_TRUE(details.did_replace_entry); | |
1994 EXPECT_EQ(1, controller.GetEntryCount()); | |
1995 } | |
1996 | |
1997 // Tests for http://crbug.com/40395 | |
1998 // Simulates this: | |
1999 // <script> | |
2000 // window.location.replace("#a"); | |
2001 // window.location='http://foo3/'; | |
2002 // </script> | |
2003 TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) { | |
2004 NavigationControllerImpl& controller = controller_impl(); | |
2005 TestNotificationTracker notifications; | |
2006 RegisterForAllNavNotifications(¬ifications, &controller); | |
2007 | |
2008 // Load an initial page. | |
2009 { | |
2010 const GURL url("http://foo/"); | |
2011 test_rvh()->SendNavigate(0, url); | |
2012 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
2013 navigation_entry_committed_counter_ = 0; | |
2014 } | |
2015 | |
2016 // Navigate to a new page. | |
2017 { | |
2018 const GURL url("http://foo2/"); | |
2019 test_rvh()->SendNavigate(1, url); | |
2020 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
2021 navigation_entry_committed_counter_ = 0; | |
2022 } | |
2023 | |
2024 // Navigate within the page. | |
2025 { | |
2026 const GURL url("http://foo2/#a"); | |
2027 ViewHostMsg_FrameNavigate_Params params; | |
2028 params.page_id = 1; // Same page_id | |
2029 params.url = url; | |
2030 params.transition = PAGE_TRANSITION_LINK; | |
2031 params.redirects.push_back(url); | |
2032 params.should_update_history = true; | |
2033 params.gesture = NavigationGestureUnknown; | |
2034 params.is_post = false; | |
2035 params.page_state = PageState::CreateFromURL(url); | |
2036 | |
2037 // This should NOT generate a new entry, nor prune the list. | |
2038 LoadCommittedDetails details; | |
2039 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
2040 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
2041 navigation_entry_committed_counter_ = 0; | |
2042 EXPECT_TRUE(details.is_in_page); | |
2043 EXPECT_TRUE(details.did_replace_entry); | |
2044 EXPECT_EQ(2, controller.GetEntryCount()); | |
2045 } | |
2046 | |
2047 // Perform a client redirect to a new page. | |
2048 { | |
2049 const GURL url("http://foo3/"); | |
2050 ViewHostMsg_FrameNavigate_Params params; | |
2051 params.page_id = 2; // New page_id | |
2052 params.url = url; | |
2053 params.transition = PAGE_TRANSITION_CLIENT_REDIRECT; | |
2054 params.redirects.push_back(GURL("http://foo2/#a")); | |
2055 params.redirects.push_back(url); | |
2056 params.should_update_history = true; | |
2057 params.gesture = NavigationGestureUnknown; | |
2058 params.is_post = false; | |
2059 params.page_state = PageState::CreateFromURL(url); | |
2060 | |
2061 // This SHOULD generate a new entry. | |
2062 LoadCommittedDetails details; | |
2063 EXPECT_TRUE(controller.RendererDidNavigate(params, &details)); | |
2064 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
2065 navigation_entry_committed_counter_ = 0; | |
2066 EXPECT_FALSE(details.is_in_page); | |
2067 EXPECT_EQ(3, controller.GetEntryCount()); | |
2068 } | |
2069 | |
2070 // Verify that BACK brings us back to http://foo2/. | |
2071 { | |
2072 const GURL url("http://foo2/"); | |
2073 controller.GoBack(); | |
2074 test_rvh()->SendNavigate(1, url); | |
2075 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
2076 navigation_entry_committed_counter_ = 0; | |
2077 EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL()); | |
2078 } | |
2079 } | |
2080 | |
2081 // NotificationObserver implementation used in verifying we've received the | |
2082 // NOTIFICATION_NAV_LIST_PRUNED method. | |
2083 class PrunedListener : public NotificationObserver { | |
2084 public: | |
2085 explicit PrunedListener(NavigationControllerImpl* controller) | |
2086 : notification_count_(0) { | |
2087 registrar_.Add(this, NOTIFICATION_NAV_LIST_PRUNED, | |
2088 Source<NavigationController>(controller)); | |
2089 } | |
2090 | |
2091 virtual void Observe(int type, | |
2092 const NotificationSource& source, | |
2093 const NotificationDetails& details) OVERRIDE { | |
2094 if (type == NOTIFICATION_NAV_LIST_PRUNED) { | |
2095 notification_count_++; | |
2096 details_ = *(Details<PrunedDetails>(details).ptr()); | |
2097 } | |
2098 } | |
2099 | |
2100 // Number of times NAV_LIST_PRUNED has been observed. | |
2101 int notification_count_; | |
2102 | |
2103 // Details from the last NAV_LIST_PRUNED. | |
2104 PrunedDetails details_; | |
2105 | |
2106 private: | |
2107 NotificationRegistrar registrar_; | |
2108 | |
2109 DISALLOW_COPY_AND_ASSIGN(PrunedListener); | |
2110 }; | |
2111 | |
2112 // Tests that we limit the number of navigation entries created correctly. | |
2113 TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) { | |
2114 NavigationControllerImpl& controller = controller_impl(); | |
2115 size_t original_count = NavigationControllerImpl::max_entry_count(); | |
2116 const int kMaxEntryCount = 5; | |
2117 | |
2118 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount); | |
2119 | |
2120 int url_index; | |
2121 // Load up to the max count, all entries should be there. | |
2122 for (url_index = 0; url_index < kMaxEntryCount; url_index++) { | |
2123 GURL url(base::StringPrintf("http://www.a.com/%d", url_index)); | |
2124 controller.LoadURL( | |
2125 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2126 test_rvh()->SendNavigate(url_index, url); | |
2127 } | |
2128 | |
2129 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount); | |
2130 | |
2131 // Created a PrunedListener to observe prune notifications. | |
2132 PrunedListener listener(&controller); | |
2133 | |
2134 // Navigate some more. | |
2135 GURL url(base::StringPrintf("http://www.a.com/%d", url_index)); | |
2136 controller.LoadURL( | |
2137 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2138 test_rvh()->SendNavigate(url_index, url); | |
2139 url_index++; | |
2140 | |
2141 // We should have got a pruned navigation. | |
2142 EXPECT_EQ(1, listener.notification_count_); | |
2143 EXPECT_TRUE(listener.details_.from_front); | |
2144 EXPECT_EQ(1, listener.details_.count); | |
2145 | |
2146 // We expect http://www.a.com/0 to be gone. | |
2147 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount); | |
2148 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), | |
2149 GURL("http:////www.a.com/1")); | |
2150 | |
2151 // More navigations. | |
2152 for (int i = 0; i < 3; i++) { | |
2153 url = GURL(base::StringPrintf("http:////www.a.com/%d", url_index)); | |
2154 controller.LoadURL( | |
2155 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2156 test_rvh()->SendNavigate(url_index, url); | |
2157 url_index++; | |
2158 } | |
2159 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount); | |
2160 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), | |
2161 GURL("http:////www.a.com/4")); | |
2162 | |
2163 NavigationControllerImpl::set_max_entry_count_for_testing(original_count); | |
2164 } | |
2165 | |
2166 // Tests that we can do a restore and navigate to the restored entries and | |
2167 // everything is updated properly. This can be tricky since there is no | |
2168 // SiteInstance for the entries created initially. | |
2169 TEST_F(NavigationControllerTest, RestoreNavigate) { | |
2170 // Create a NavigationController with a restored set of tabs. | |
2171 GURL url("http://foo"); | |
2172 std::vector<NavigationEntry*> entries; | |
2173 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry( | |
2174 url, Referrer(), PAGE_TRANSITION_RELOAD, false, std::string(), | |
2175 browser_context()); | |
2176 entry->SetPageID(0); | |
2177 entry->SetTitle(ASCIIToUTF16("Title")); | |
2178 entry->SetPageState(PageState::CreateFromEncodedData("state")); | |
2179 const base::Time timestamp = base::Time::Now(); | |
2180 entry->SetTimestamp(timestamp); | |
2181 entries.push_back(entry); | |
2182 scoped_ptr<WebContentsImpl> our_contents(static_cast<WebContentsImpl*>( | |
2183 WebContents::Create(WebContents::CreateParams(browser_context())))); | |
2184 NavigationControllerImpl& our_controller = our_contents->GetController(); | |
2185 our_controller.Restore( | |
2186 0, | |
2187 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY, | |
2188 &entries); | |
2189 ASSERT_EQ(0u, entries.size()); | |
2190 | |
2191 // Before navigating to the restored entry, it should have a restore_type | |
2192 // and no SiteInstance. | |
2193 ASSERT_EQ(1, our_controller.GetEntryCount()); | |
2194 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY, | |
2195 NavigationEntryImpl::FromNavigationEntry( | |
2196 our_controller.GetEntryAtIndex(0))->restore_type()); | |
2197 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry( | |
2198 our_controller.GetEntryAtIndex(0))->site_instance()); | |
2199 | |
2200 // After navigating, we should have one entry, and it should be "pending". | |
2201 // It should now have a SiteInstance and no restore_type. | |
2202 our_controller.GoToIndex(0); | |
2203 EXPECT_EQ(1, our_controller.GetEntryCount()); | |
2204 EXPECT_EQ(our_controller.GetEntryAtIndex(0), | |
2205 our_controller.GetPendingEntry()); | |
2206 EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID()); | |
2207 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE, | |
2208 NavigationEntryImpl::FromNavigationEntry | |
2209 (our_controller.GetEntryAtIndex(0))->restore_type()); | |
2210 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry( | |
2211 our_controller.GetEntryAtIndex(0))->site_instance()); | |
2212 | |
2213 // Timestamp should remain the same before the navigation finishes. | |
2214 EXPECT_EQ(timestamp, our_controller.GetEntryAtIndex(0)->GetTimestamp()); | |
2215 | |
2216 // Say we navigated to that entry. | |
2217 ViewHostMsg_FrameNavigate_Params params; | |
2218 params.page_id = 0; | |
2219 params.url = url; | |
2220 params.transition = PAGE_TRANSITION_LINK; | |
2221 params.should_update_history = false; | |
2222 params.gesture = NavigationGestureUser; | |
2223 params.is_post = false; | |
2224 params.page_state = PageState::CreateFromURL(url); | |
2225 LoadCommittedDetails details; | |
2226 our_controller.RendererDidNavigate(params, &details); | |
2227 | |
2228 // There should be no longer any pending entry and one committed one. This | |
2229 // means that we were able to locate the entry, assign its site instance, and | |
2230 // commit it properly. | |
2231 EXPECT_EQ(1, our_controller.GetEntryCount()); | |
2232 EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex()); | |
2233 EXPECT_FALSE(our_controller.GetPendingEntry()); | |
2234 EXPECT_EQ(url, | |
2235 NavigationEntryImpl::FromNavigationEntry( | |
2236 our_controller.GetLastCommittedEntry())->site_instance()-> | |
2237 GetSiteURL()); | |
2238 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE, | |
2239 NavigationEntryImpl::FromNavigationEntry( | |
2240 our_controller.GetEntryAtIndex(0))->restore_type()); | |
2241 | |
2242 // Timestamp should have been updated. | |
2243 EXPECT_GE(our_controller.GetEntryAtIndex(0)->GetTimestamp(), timestamp); | |
2244 } | |
2245 | |
2246 // Tests that we can still navigate to a restored entry after a different | |
2247 // navigation fails and clears the pending entry. http://crbug.com/90085 | |
2248 TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) { | |
2249 // Create a NavigationController with a restored set of tabs. | |
2250 GURL url("http://foo"); | |
2251 std::vector<NavigationEntry*> entries; | |
2252 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry( | |
2253 url, Referrer(), PAGE_TRANSITION_RELOAD, false, std::string(), | |
2254 browser_context()); | |
2255 entry->SetPageID(0); | |
2256 entry->SetTitle(ASCIIToUTF16("Title")); | |
2257 entry->SetPageState(PageState::CreateFromEncodedData("state")); | |
2258 entries.push_back(entry); | |
2259 scoped_ptr<WebContentsImpl> our_contents(static_cast<WebContentsImpl*>( | |
2260 WebContents::Create(WebContents::CreateParams(browser_context())))); | |
2261 NavigationControllerImpl& our_controller = our_contents->GetController(); | |
2262 our_controller.Restore( | |
2263 0, NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY, &entries); | |
2264 ASSERT_EQ(0u, entries.size()); | |
2265 | |
2266 // Before navigating to the restored entry, it should have a restore_type | |
2267 // and no SiteInstance. | |
2268 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY, | |
2269 NavigationEntryImpl::FromNavigationEntry( | |
2270 our_controller.GetEntryAtIndex(0))->restore_type()); | |
2271 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry( | |
2272 our_controller.GetEntryAtIndex(0))->site_instance()); | |
2273 | |
2274 // After navigating, we should have one entry, and it should be "pending". | |
2275 // It should now have a SiteInstance and no restore_type. | |
2276 our_controller.GoToIndex(0); | |
2277 EXPECT_EQ(1, our_controller.GetEntryCount()); | |
2278 EXPECT_EQ(our_controller.GetEntryAtIndex(0), | |
2279 our_controller.GetPendingEntry()); | |
2280 EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID()); | |
2281 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE, | |
2282 NavigationEntryImpl::FromNavigationEntry( | |
2283 our_controller.GetEntryAtIndex(0))->restore_type()); | |
2284 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry( | |
2285 our_controller.GetEntryAtIndex(0))->site_instance()); | |
2286 | |
2287 // This pending navigation may have caused a different navigation to fail, | |
2288 // which causes the pending entry to be cleared. | |
2289 TestRenderViewHost* rvh = | |
2290 static_cast<TestRenderViewHost*>(our_contents->GetRenderViewHost()); | |
2291 ViewHostMsg_DidFailProvisionalLoadWithError_Params fail_load_params; | |
2292 fail_load_params.frame_id = 1; | |
2293 fail_load_params.is_main_frame = true; | |
2294 fail_load_params.error_code = net::ERR_ABORTED; | |
2295 fail_load_params.error_description = string16(); | |
2296 fail_load_params.url = url; | |
2297 fail_load_params.showing_repost_interstitial = false; | |
2298 rvh->OnMessageReceived( | |
2299 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id | |
2300 fail_load_params)); | |
2301 | |
2302 // Now the pending restored entry commits. | |
2303 ViewHostMsg_FrameNavigate_Params params; | |
2304 params.page_id = 0; | |
2305 params.url = url; | |
2306 params.transition = PAGE_TRANSITION_LINK; | |
2307 params.should_update_history = false; | |
2308 params.gesture = NavigationGestureUser; | |
2309 params.is_post = false; | |
2310 params.page_state = PageState::CreateFromURL(url); | |
2311 LoadCommittedDetails details; | |
2312 our_controller.RendererDidNavigate(params, &details); | |
2313 | |
2314 // There should be no pending entry and one committed one. | |
2315 EXPECT_EQ(1, our_controller.GetEntryCount()); | |
2316 EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex()); | |
2317 EXPECT_FALSE(our_controller.GetPendingEntry()); | |
2318 EXPECT_EQ(url, | |
2319 NavigationEntryImpl::FromNavigationEntry( | |
2320 our_controller.GetLastCommittedEntry())->site_instance()-> | |
2321 GetSiteURL()); | |
2322 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE, | |
2323 NavigationEntryImpl::FromNavigationEntry( | |
2324 our_controller.GetEntryAtIndex(0))->restore_type()); | |
2325 } | |
2326 | |
2327 // Make sure that the page type and stuff is correct after an interstitial. | |
2328 TEST_F(NavigationControllerTest, Interstitial) { | |
2329 NavigationControllerImpl& controller = controller_impl(); | |
2330 // First navigate somewhere normal. | |
2331 const GURL url1("http://foo"); | |
2332 controller.LoadURL( | |
2333 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2334 test_rvh()->SendNavigate(0, url1); | |
2335 | |
2336 // Now navigate somewhere with an interstitial. | |
2337 const GURL url2("http://bar"); | |
2338 controller.LoadURL( | |
2339 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2340 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())-> | |
2341 set_page_type(PAGE_TYPE_INTERSTITIAL); | |
2342 | |
2343 // At this point the interstitial will be displayed and the load will still | |
2344 // be pending. If the user continues, the load will commit. | |
2345 test_rvh()->SendNavigate(1, url2); | |
2346 | |
2347 // The page should be a normal page again. | |
2348 EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL()); | |
2349 EXPECT_EQ(PAGE_TYPE_NORMAL, | |
2350 controller.GetLastCommittedEntry()->GetPageType()); | |
2351 } | |
2352 | |
2353 TEST_F(NavigationControllerTest, RemoveEntry) { | |
2354 NavigationControllerImpl& controller = controller_impl(); | |
2355 const GURL url1("http://foo/1"); | |
2356 const GURL url2("http://foo/2"); | |
2357 const GURL url3("http://foo/3"); | |
2358 const GURL url4("http://foo/4"); | |
2359 const GURL url5("http://foo/5"); | |
2360 const GURL pending_url("http://foo/pending"); | |
2361 const GURL default_url("http://foo/default"); | |
2362 | |
2363 controller.LoadURL( | |
2364 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2365 test_rvh()->SendNavigate(0, url1); | |
2366 controller.LoadURL( | |
2367 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2368 test_rvh()->SendNavigate(1, url2); | |
2369 controller.LoadURL( | |
2370 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2371 test_rvh()->SendNavigate(2, url3); | |
2372 controller.LoadURL( | |
2373 url4, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2374 test_rvh()->SendNavigate(3, url4); | |
2375 controller.LoadURL( | |
2376 url5, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2377 test_rvh()->SendNavigate(4, url5); | |
2378 | |
2379 // Try to remove the last entry. Will fail because it is the current entry. | |
2380 EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1)); | |
2381 EXPECT_EQ(5, controller.GetEntryCount()); | |
2382 EXPECT_EQ(4, controller.GetLastCommittedEntryIndex()); | |
2383 | |
2384 // Go back, but don't commit yet. Check that we can't delete the current | |
2385 // and pending entries. | |
2386 controller.GoBack(); | |
2387 EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1)); | |
2388 EXPECT_FALSE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 2)); | |
2389 | |
2390 // Now commit and delete the last entry. | |
2391 test_rvh()->SendNavigate(3, url4); | |
2392 EXPECT_TRUE(controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1)); | |
2393 EXPECT_EQ(4, controller.GetEntryCount()); | |
2394 EXPECT_EQ(3, controller.GetLastCommittedEntryIndex()); | |
2395 EXPECT_FALSE(controller.GetPendingEntry()); | |
2396 | |
2397 // Remove an entry which is not the last committed one. | |
2398 EXPECT_TRUE(controller.RemoveEntryAtIndex(0)); | |
2399 EXPECT_EQ(3, controller.GetEntryCount()); | |
2400 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex()); | |
2401 EXPECT_FALSE(controller.GetPendingEntry()); | |
2402 | |
2403 // Remove the 2 remaining entries. | |
2404 controller.RemoveEntryAtIndex(1); | |
2405 controller.RemoveEntryAtIndex(0); | |
2406 | |
2407 // This should leave us with only the last committed entry. | |
2408 EXPECT_EQ(1, controller.GetEntryCount()); | |
2409 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); | |
2410 } | |
2411 | |
2412 // Tests the transient entry, making sure it goes away with all navigations. | |
2413 TEST_F(NavigationControllerTest, TransientEntry) { | |
2414 NavigationControllerImpl& controller = controller_impl(); | |
2415 TestNotificationTracker notifications; | |
2416 RegisterForAllNavNotifications(¬ifications, &controller); | |
2417 | |
2418 const GURL url0("http://foo/0"); | |
2419 const GURL url1("http://foo/1"); | |
2420 const GURL url2("http://foo/2"); | |
2421 const GURL url3("http://foo/3"); | |
2422 const GURL url3_ref("http://foo/3#bar"); | |
2423 const GURL url4("http://foo/4"); | |
2424 const GURL transient_url("http://foo/transient"); | |
2425 | |
2426 controller.LoadURL( | |
2427 url0, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2428 test_rvh()->SendNavigate(0, url0); | |
2429 controller.LoadURL( | |
2430 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2431 test_rvh()->SendNavigate(1, url1); | |
2432 | |
2433 notifications.Reset(); | |
2434 | |
2435 // Adding a transient with no pending entry. | |
2436 NavigationEntryImpl* transient_entry = new NavigationEntryImpl; | |
2437 transient_entry->SetURL(transient_url); | |
2438 controller.SetTransientEntry(transient_entry); | |
2439 | |
2440 // We should not have received any notifications. | |
2441 EXPECT_EQ(0U, notifications.size()); | |
2442 | |
2443 // Check our state. | |
2444 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); | |
2445 EXPECT_EQ(controller.GetEntryCount(), 3); | |
2446 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1); | |
2447 EXPECT_EQ(controller.GetPendingEntryIndex(), -1); | |
2448 EXPECT_TRUE(controller.GetLastCommittedEntry()); | |
2449 EXPECT_FALSE(controller.GetPendingEntry()); | |
2450 EXPECT_TRUE(controller.CanGoBack()); | |
2451 EXPECT_FALSE(controller.CanGoForward()); | |
2452 EXPECT_EQ(contents()->GetMaxPageID(), 1); | |
2453 | |
2454 // Navigate. | |
2455 controller.LoadURL( | |
2456 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2457 test_rvh()->SendNavigate(2, url2); | |
2458 | |
2459 // We should have navigated, transient entry should be gone. | |
2460 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL()); | |
2461 EXPECT_EQ(controller.GetEntryCount(), 3); | |
2462 | |
2463 // Add a transient again, then navigate with no pending entry this time. | |
2464 transient_entry = new NavigationEntryImpl; | |
2465 transient_entry->SetURL(transient_url); | |
2466 controller.SetTransientEntry(transient_entry); | |
2467 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); | |
2468 test_rvh()->SendNavigate(3, url3); | |
2469 // Transient entry should be gone. | |
2470 EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL()); | |
2471 EXPECT_EQ(controller.GetEntryCount(), 4); | |
2472 | |
2473 // Initiate a navigation, add a transient then commit navigation. | |
2474 controller.LoadURL( | |
2475 url4, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2476 transient_entry = new NavigationEntryImpl; | |
2477 transient_entry->SetURL(transient_url); | |
2478 controller.SetTransientEntry(transient_entry); | |
2479 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); | |
2480 test_rvh()->SendNavigate(4, url4); | |
2481 EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL()); | |
2482 EXPECT_EQ(controller.GetEntryCount(), 5); | |
2483 | |
2484 // Add a transient and go back. This should simply remove the transient. | |
2485 transient_entry = new NavigationEntryImpl; | |
2486 transient_entry->SetURL(transient_url); | |
2487 controller.SetTransientEntry(transient_entry); | |
2488 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); | |
2489 EXPECT_TRUE(controller.CanGoBack()); | |
2490 EXPECT_FALSE(controller.CanGoForward()); | |
2491 controller.GoBack(); | |
2492 // Transient entry should be gone. | |
2493 EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL()); | |
2494 EXPECT_EQ(controller.GetEntryCount(), 5); | |
2495 test_rvh()->SendNavigate(3, url3); | |
2496 | |
2497 // Add a transient and go to an entry before the current one. | |
2498 transient_entry = new NavigationEntryImpl; | |
2499 transient_entry->SetURL(transient_url); | |
2500 controller.SetTransientEntry(transient_entry); | |
2501 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); | |
2502 controller.GoToIndex(1); | |
2503 // The navigation should have been initiated, transient entry should be gone. | |
2504 EXPECT_FALSE(controller.GetTransientEntry()); | |
2505 EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL()); | |
2506 // Visible entry does not update for history navigations until commit. | |
2507 EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL()); | |
2508 test_rvh()->SendNavigate(1, url1); | |
2509 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL()); | |
2510 | |
2511 // Add a transient and go to an entry after the current one. | |
2512 transient_entry = new NavigationEntryImpl; | |
2513 transient_entry->SetURL(transient_url); | |
2514 controller.SetTransientEntry(transient_entry); | |
2515 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); | |
2516 controller.GoToIndex(3); | |
2517 // The navigation should have been initiated, transient entry should be gone. | |
2518 // Because of the transient entry that is removed, going to index 3 makes us | |
2519 // land on url2 (which is visible after the commit). | |
2520 EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL()); | |
2521 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL()); | |
2522 test_rvh()->SendNavigate(2, url2); | |
2523 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL()); | |
2524 | |
2525 // Add a transient and go forward. | |
2526 transient_entry = new NavigationEntryImpl; | |
2527 transient_entry->SetURL(transient_url); | |
2528 controller.SetTransientEntry(transient_entry); | |
2529 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); | |
2530 EXPECT_TRUE(controller.CanGoForward()); | |
2531 controller.GoForward(); | |
2532 // We should have navigated, transient entry should be gone. | |
2533 EXPECT_FALSE(controller.GetTransientEntry()); | |
2534 EXPECT_EQ(url3, controller.GetPendingEntry()->GetURL()); | |
2535 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL()); | |
2536 test_rvh()->SendNavigate(3, url3); | |
2537 EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL()); | |
2538 | |
2539 // Add a transient and do an in-page navigation, replacing the current entry. | |
2540 transient_entry = new NavigationEntryImpl; | |
2541 transient_entry->SetURL(transient_url); | |
2542 controller.SetTransientEntry(transient_entry); | |
2543 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); | |
2544 test_rvh()->SendNavigate(3, url3_ref); | |
2545 // Transient entry should be gone. | |
2546 EXPECT_FALSE(controller.GetTransientEntry()); | |
2547 EXPECT_EQ(url3_ref, controller.GetVisibleEntry()->GetURL()); | |
2548 | |
2549 // Ensure the URLs are correct. | |
2550 EXPECT_EQ(controller.GetEntryCount(), 5); | |
2551 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0); | |
2552 EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), url1); | |
2553 EXPECT_EQ(controller.GetEntryAtIndex(2)->GetURL(), url2); | |
2554 EXPECT_EQ(controller.GetEntryAtIndex(3)->GetURL(), url3_ref); | |
2555 EXPECT_EQ(controller.GetEntryAtIndex(4)->GetURL(), url4); | |
2556 } | |
2557 | |
2558 // Test that Reload initiates a new navigation to a transient entry's URL. | |
2559 TEST_F(NavigationControllerTest, ReloadTransient) { | |
2560 NavigationControllerImpl& controller = controller_impl(); | |
2561 const GURL url0("http://foo/0"); | |
2562 const GURL url1("http://foo/1"); | |
2563 const GURL transient_url("http://foo/transient"); | |
2564 | |
2565 // Load |url0|, and start a pending navigation to |url1|. | |
2566 controller.LoadURL( | |
2567 url0, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2568 test_rvh()->SendNavigate(0, url0); | |
2569 controller.LoadURL( | |
2570 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2571 | |
2572 // A transient entry is added, interrupting the navigation. | |
2573 NavigationEntryImpl* transient_entry = new NavigationEntryImpl; | |
2574 transient_entry->SetURL(transient_url); | |
2575 controller.SetTransientEntry(transient_entry); | |
2576 EXPECT_TRUE(controller.GetTransientEntry()); | |
2577 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); | |
2578 | |
2579 // The page is reloaded, which should remove the pending entry for |url1| and | |
2580 // the transient entry for |transient_url|, and start a navigation to | |
2581 // |transient_url|. | |
2582 controller.Reload(true); | |
2583 EXPECT_FALSE(controller.GetTransientEntry()); | |
2584 EXPECT_TRUE(controller.GetPendingEntry()); | |
2585 EXPECT_EQ(transient_url, controller.GetVisibleEntry()->GetURL()); | |
2586 ASSERT_EQ(controller.GetEntryCount(), 1); | |
2587 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0); | |
2588 | |
2589 // Load of |transient_url| completes. | |
2590 test_rvh()->SendNavigate(1, transient_url); | |
2591 ASSERT_EQ(controller.GetEntryCount(), 2); | |
2592 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0); | |
2593 EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), transient_url); | |
2594 } | |
2595 | |
2596 // Ensure that renderer initiated pending entries get replaced, so that we | |
2597 // don't show a stale virtual URL when a navigation commits. | |
2598 // See http://crbug.com/266922. | |
2599 TEST_F(NavigationControllerTest, RendererInitiatedPendingEntries) { | |
2600 NavigationControllerImpl& controller = controller_impl(); | |
2601 | |
2602 const GURL url1("nonexistent:12121"); | |
2603 const GURL url1_fixed("http://nonexistent:12121/"); | |
2604 const GURL url2("http://foo"); | |
2605 | |
2606 // We create pending entries for renderer-initiated navigations so that we | |
2607 // can show them in new tabs when it is safe. | |
2608 contents()->DidStartProvisionalLoadForFrame( | |
2609 test_rvh(), 1, -1, true, url1); | |
2610 | |
2611 // Simulate what happens if a BrowserURLHandler rewrites the URL, causing | |
2612 // the virtual URL to differ from the URL. | |
2613 controller.GetPendingEntry()->SetURL(url1_fixed); | |
2614 controller.GetPendingEntry()->SetVirtualURL(url1); | |
2615 | |
2616 EXPECT_EQ(url1_fixed, controller.GetPendingEntry()->GetURL()); | |
2617 EXPECT_EQ(url1, controller.GetPendingEntry()->GetVirtualURL()); | |
2618 EXPECT_TRUE( | |
2619 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())-> | |
2620 is_renderer_initiated()); | |
2621 | |
2622 // If the user clicks another link, we should replace the pending entry. | |
2623 contents()->DidStartProvisionalLoadForFrame( | |
2624 test_rvh(), 1, -1, true, url2); | |
2625 EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL()); | |
2626 EXPECT_EQ(url2, controller.GetPendingEntry()->GetVirtualURL()); | |
2627 | |
2628 // Once it commits, the URL and virtual URL should reflect the actual page. | |
2629 test_rvh()->SendNavigate(0, url2); | |
2630 EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL()); | |
2631 EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetVirtualURL()); | |
2632 | |
2633 // We should not replace the pending entry for an error URL. | |
2634 contents()->DidStartProvisionalLoadForFrame( | |
2635 test_rvh(), 1, -1, true, url1); | |
2636 EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL()); | |
2637 contents()->DidStartProvisionalLoadForFrame( | |
2638 test_rvh(), 1, -1, true, GURL(kUnreachableWebDataURL)); | |
2639 EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL()); | |
2640 | |
2641 // We should remember if the pending entry will replace the current one. | |
2642 // http://crbug.com/308444. | |
2643 contents()->DidStartProvisionalLoadForFrame( | |
2644 test_rvh(), 1, -1, true, url1); | |
2645 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())-> | |
2646 set_should_replace_entry(true); | |
2647 contents()->DidStartProvisionalLoadForFrame( | |
2648 test_rvh(), 1, -1, true, url2); | |
2649 EXPECT_TRUE( | |
2650 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())-> | |
2651 should_replace_entry()); | |
2652 test_rvh()->SendNavigate(0, url2); | |
2653 EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL()); | |
2654 } | |
2655 | |
2656 // Tests that the URLs for renderer-initiated navigations are not displayed to | |
2657 // the user until the navigation commits, to prevent URL spoof attacks. | |
2658 // See http://crbug.com/99016. | |
2659 TEST_F(NavigationControllerTest, DontShowRendererURLUntilCommit) { | |
2660 NavigationControllerImpl& controller = controller_impl(); | |
2661 TestNotificationTracker notifications; | |
2662 RegisterForAllNavNotifications(¬ifications, &controller); | |
2663 | |
2664 const GURL url0("http://foo/0"); | |
2665 const GURL url1("http://foo/1"); | |
2666 | |
2667 // For typed navigations (browser-initiated), both pending and visible entries | |
2668 // should update before commit. | |
2669 controller.LoadURL(url0, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2670 EXPECT_EQ(url0, controller.GetPendingEntry()->GetURL()); | |
2671 EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL()); | |
2672 test_rvh()->SendNavigate(0, url0); | |
2673 | |
2674 // For link clicks (renderer-initiated navigations), the pending entry should | |
2675 // update before commit but the visible should not. | |
2676 NavigationController::LoadURLParams load_url_params(url1); | |
2677 load_url_params.is_renderer_initiated = true; | |
2678 controller.LoadURLWithParams(load_url_params); | |
2679 EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL()); | |
2680 EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL()); | |
2681 EXPECT_TRUE( | |
2682 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())-> | |
2683 is_renderer_initiated()); | |
2684 | |
2685 // After commit, both visible should be updated, there should be no pending | |
2686 // entry, and we should no longer treat the entry as renderer-initiated. | |
2687 test_rvh()->SendNavigate(1, url1); | |
2688 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL()); | |
2689 EXPECT_FALSE(controller.GetPendingEntry()); | |
2690 EXPECT_FALSE( | |
2691 NavigationEntryImpl::FromNavigationEntry( | |
2692 controller.GetLastCommittedEntry())->is_renderer_initiated()); | |
2693 | |
2694 notifications.Reset(); | |
2695 } | |
2696 | |
2697 // Tests that the URLs for renderer-initiated navigations in new tabs are | |
2698 // displayed to the user before commit, as long as the initial about:blank | |
2699 // page has not been modified. If so, we must revert to showing about:blank. | |
2700 // See http://crbug.com/9682. | |
2701 TEST_F(NavigationControllerTest, ShowRendererURLInNewTabUntilModified) { | |
2702 NavigationControllerImpl& controller = controller_impl(); | |
2703 TestNotificationTracker notifications; | |
2704 RegisterForAllNavNotifications(¬ifications, &controller); | |
2705 | |
2706 const GURL url("http://foo"); | |
2707 | |
2708 // For renderer-initiated navigations in new tabs (with no committed entries), | |
2709 // we show the pending entry's URL as long as the about:blank page is not | |
2710 // modified. | |
2711 NavigationController::LoadURLParams load_url_params(url); | |
2712 load_url_params.transition_type = PAGE_TRANSITION_LINK; | |
2713 load_url_params.is_renderer_initiated = true; | |
2714 controller.LoadURLWithParams(load_url_params); | |
2715 EXPECT_EQ(url, controller.GetVisibleEntry()->GetURL()); | |
2716 EXPECT_EQ(url, controller.GetPendingEntry()->GetURL()); | |
2717 EXPECT_TRUE( | |
2718 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())-> | |
2719 is_renderer_initiated()); | |
2720 EXPECT_TRUE(controller.IsInitialNavigation()); | |
2721 EXPECT_FALSE(test_rvh()->has_accessed_initial_document()); | |
2722 | |
2723 // There should be no title yet. | |
2724 EXPECT_TRUE(contents()->GetTitle().empty()); | |
2725 | |
2726 // If something else modifies the contents of the about:blank page, then | |
2727 // we must revert to showing about:blank to avoid a URL spoof. | |
2728 test_rvh()->OnMessageReceived( | |
2729 ViewHostMsg_DidAccessInitialDocument(0)); | |
2730 EXPECT_TRUE(test_rvh()->has_accessed_initial_document()); | |
2731 EXPECT_FALSE(controller.GetVisibleEntry()); | |
2732 EXPECT_EQ(url, controller.GetPendingEntry()->GetURL()); | |
2733 | |
2734 notifications.Reset(); | |
2735 } | |
2736 | |
2737 TEST_F(NavigationControllerTest, DontShowRendererURLInNewTabAfterCommit) { | |
2738 NavigationControllerImpl& controller = controller_impl(); | |
2739 TestNotificationTracker notifications; | |
2740 RegisterForAllNavNotifications(¬ifications, &controller); | |
2741 | |
2742 const GURL url1("http://foo/eh"); | |
2743 const GURL url2("http://foo/bee"); | |
2744 | |
2745 // For renderer-initiated navigations in new tabs (with no committed entries), | |
2746 // we show the pending entry's URL as long as the about:blank page is not | |
2747 // modified. | |
2748 NavigationController::LoadURLParams load_url_params(url1); | |
2749 load_url_params.transition_type = PAGE_TRANSITION_LINK; | |
2750 load_url_params.is_renderer_initiated = true; | |
2751 controller.LoadURLWithParams(load_url_params); | |
2752 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL()); | |
2753 EXPECT_TRUE( | |
2754 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())-> | |
2755 is_renderer_initiated()); | |
2756 EXPECT_TRUE(controller.IsInitialNavigation()); | |
2757 EXPECT_FALSE(test_rvh()->has_accessed_initial_document()); | |
2758 | |
2759 // Simulate a commit and then starting a new pending navigation. | |
2760 test_rvh()->SendNavigate(0, url1); | |
2761 NavigationController::LoadURLParams load_url2_params(url2); | |
2762 load_url2_params.transition_type = PAGE_TRANSITION_LINK; | |
2763 load_url2_params.is_renderer_initiated = true; | |
2764 controller.LoadURLWithParams(load_url2_params); | |
2765 | |
2766 // We should not consider this an initial navigation, and thus should | |
2767 // not show the pending URL. | |
2768 EXPECT_FALSE(test_rvh()->has_accessed_initial_document()); | |
2769 EXPECT_FALSE(controller.IsInitialNavigation()); | |
2770 EXPECT_TRUE(controller.GetVisibleEntry()); | |
2771 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL()); | |
2772 | |
2773 notifications.Reset(); | |
2774 } | |
2775 | |
2776 // Tests that IsInPageNavigation returns appropriate results. Prevents | |
2777 // regression for bug 1126349. | |
2778 TEST_F(NavigationControllerTest, IsInPageNavigation) { | |
2779 NavigationControllerImpl& controller = controller_impl(); | |
2780 // Navigate to URL with no refs. | |
2781 const GURL url("http://www.google.com/home.html"); | |
2782 test_rvh()->SendNavigate(0, url); | |
2783 | |
2784 // Reloading the page is not an in-page navigation. | |
2785 EXPECT_FALSE(controller.IsURLInPageNavigation(url)); | |
2786 const GURL other_url("http://www.google.com/add.html"); | |
2787 EXPECT_FALSE(controller.IsURLInPageNavigation(other_url)); | |
2788 const GURL url_with_ref("http://www.google.com/home.html#my_ref"); | |
2789 EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref)); | |
2790 | |
2791 // Navigate to URL with refs. | |
2792 test_rvh()->SendNavigate(1, url_with_ref); | |
2793 | |
2794 // Reloading the page is not an in-page navigation. | |
2795 EXPECT_FALSE(controller.IsURLInPageNavigation(url_with_ref)); | |
2796 EXPECT_FALSE(controller.IsURLInPageNavigation(url)); | |
2797 EXPECT_FALSE(controller.IsURLInPageNavigation(other_url)); | |
2798 const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref"); | |
2799 EXPECT_TRUE(controller.IsURLInPageNavigation(other_url_with_ref)); | |
2800 | |
2801 // Going to the same url again will be considered in-page | |
2802 // if the renderer says it is even if the navigation type isn't IN_PAGE. | |
2803 EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref, true, | |
2804 NAVIGATION_TYPE_UNKNOWN)); | |
2805 | |
2806 // Going back to the non ref url will be considered in-page if the navigation | |
2807 // type is IN_PAGE. | |
2808 EXPECT_TRUE(controller.IsURLInPageNavigation(url, true, | |
2809 NAVIGATION_TYPE_IN_PAGE)); | |
2810 } | |
2811 | |
2812 // Some pages can have subframes with the same base URL (minus the reference) as | |
2813 // the main page. Even though this is hard, it can happen, and we don't want | |
2814 // these subframe navigations to affect the toplevel document. They should | |
2815 // instead be ignored. http://crbug.com/5585 | |
2816 TEST_F(NavigationControllerTest, SameSubframe) { | |
2817 NavigationControllerImpl& controller = controller_impl(); | |
2818 // Navigate the main frame. | |
2819 const GURL url("http://www.google.com/"); | |
2820 test_rvh()->SendNavigate(0, url); | |
2821 | |
2822 // We should be at the first navigation entry. | |
2823 EXPECT_EQ(controller.GetEntryCount(), 1); | |
2824 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
2825 | |
2826 // Navigate a subframe that would normally count as in-page. | |
2827 const GURL subframe("http://www.google.com/#"); | |
2828 ViewHostMsg_FrameNavigate_Params params; | |
2829 params.page_id = 0; | |
2830 params.url = subframe; | |
2831 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME; | |
2832 params.should_update_history = false; | |
2833 params.gesture = NavigationGestureAuto; | |
2834 params.is_post = false; | |
2835 params.page_state = PageState::CreateFromURL(subframe); | |
2836 LoadCommittedDetails details; | |
2837 EXPECT_FALSE(controller.RendererDidNavigate(params, &details)); | |
2838 | |
2839 // Nothing should have changed. | |
2840 EXPECT_EQ(controller.GetEntryCount(), 1); | |
2841 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0); | |
2842 } | |
2843 | |
2844 // Make sure that on cloning a WebContentsImpl and going back needs_reload is | |
2845 // false. | |
2846 TEST_F(NavigationControllerTest, CloneAndGoBack) { | |
2847 NavigationControllerImpl& controller = controller_impl(); | |
2848 const GURL url1("http://foo1"); | |
2849 const GURL url2("http://foo2"); | |
2850 const string16 title(ASCIIToUTF16("Title")); | |
2851 | |
2852 NavigateAndCommit(url1); | |
2853 controller.GetVisibleEntry()->SetTitle(title); | |
2854 NavigateAndCommit(url2); | |
2855 | |
2856 scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone()); | |
2857 | |
2858 ASSERT_EQ(2, clone->GetController().GetEntryCount()); | |
2859 EXPECT_TRUE(clone->GetController().NeedsReload()); | |
2860 clone->GetController().GoBack(); | |
2861 // Navigating back should have triggered needs_reload_ to go false. | |
2862 EXPECT_FALSE(clone->GetController().NeedsReload()); | |
2863 | |
2864 // Ensure that the pending URL and its title are visible. | |
2865 EXPECT_EQ(url1, clone->GetController().GetVisibleEntry()->GetURL()); | |
2866 EXPECT_EQ(title, clone->GetTitle()); | |
2867 } | |
2868 | |
2869 // Make sure that reloading a cloned tab doesn't change its pending entry index. | |
2870 // See http://crbug.com/234491. | |
2871 TEST_F(NavigationControllerTest, CloneAndReload) { | |
2872 NavigationControllerImpl& controller = controller_impl(); | |
2873 const GURL url1("http://foo1"); | |
2874 const GURL url2("http://foo2"); | |
2875 const string16 title(ASCIIToUTF16("Title")); | |
2876 | |
2877 NavigateAndCommit(url1); | |
2878 controller.GetVisibleEntry()->SetTitle(title); | |
2879 NavigateAndCommit(url2); | |
2880 | |
2881 scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone()); | |
2882 clone->GetController().LoadIfNecessary(); | |
2883 | |
2884 ASSERT_EQ(2, clone->GetController().GetEntryCount()); | |
2885 EXPECT_EQ(1, clone->GetController().GetPendingEntryIndex()); | |
2886 | |
2887 clone->GetController().Reload(true); | |
2888 EXPECT_EQ(1, clone->GetController().GetPendingEntryIndex()); | |
2889 } | |
2890 | |
2891 // Make sure that cloning a WebContentsImpl doesn't copy interstitials. | |
2892 TEST_F(NavigationControllerTest, CloneOmitsInterstitials) { | |
2893 NavigationControllerImpl& controller = controller_impl(); | |
2894 const GURL url1("http://foo1"); | |
2895 const GURL url2("http://foo2"); | |
2896 | |
2897 NavigateAndCommit(url1); | |
2898 NavigateAndCommit(url2); | |
2899 | |
2900 // Add an interstitial entry. Should be deleted with controller. | |
2901 NavigationEntryImpl* interstitial_entry = new NavigationEntryImpl(); | |
2902 interstitial_entry->set_page_type(PAGE_TYPE_INTERSTITIAL); | |
2903 controller.SetTransientEntry(interstitial_entry); | |
2904 | |
2905 scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone()); | |
2906 | |
2907 ASSERT_EQ(2, clone->GetController().GetEntryCount()); | |
2908 } | |
2909 | |
2910 // Test requesting and triggering a lazy reload. | |
2911 TEST_F(NavigationControllerTest, LazyReload) { | |
2912 NavigationControllerImpl& controller = controller_impl(); | |
2913 const GURL url("http://foo"); | |
2914 NavigateAndCommit(url); | |
2915 ASSERT_FALSE(controller.NeedsReload()); | |
2916 | |
2917 // Request a reload to happen when the controller becomes active (e.g. after | |
2918 // the renderer gets killed in background on Android). | |
2919 controller.SetNeedsReload(); | |
2920 ASSERT_TRUE(controller.NeedsReload()); | |
2921 | |
2922 // Set the controller as active, triggering the requested reload. | |
2923 controller.SetActive(true); | |
2924 ASSERT_FALSE(controller.NeedsReload()); | |
2925 } | |
2926 | |
2927 // Tests a subframe navigation while a toplevel navigation is pending. | |
2928 // http://crbug.com/43967 | |
2929 TEST_F(NavigationControllerTest, SubframeWhilePending) { | |
2930 NavigationControllerImpl& controller = controller_impl(); | |
2931 // Load the first page. | |
2932 const GURL url1("http://foo/"); | |
2933 NavigateAndCommit(url1); | |
2934 | |
2935 // Now start a pending load to a totally different page, but don't commit it. | |
2936 const GURL url2("http://bar/"); | |
2937 controller.LoadURL( | |
2938 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
2939 | |
2940 // Send a subframe update from the first page, as if one had just | |
2941 // automatically loaded. Auto subframes don't increment the page ID. | |
2942 const GURL url1_sub("http://foo/subframe"); | |
2943 ViewHostMsg_FrameNavigate_Params params; | |
2944 params.page_id = controller.GetLastCommittedEntry()->GetPageID(); | |
2945 params.url = url1_sub; | |
2946 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME; | |
2947 params.should_update_history = false; | |
2948 params.gesture = NavigationGestureAuto; | |
2949 params.is_post = false; | |
2950 params.page_state = PageState::CreateFromURL(url1_sub); | |
2951 LoadCommittedDetails details; | |
2952 | |
2953 // This should return false meaning that nothing was actually updated. | |
2954 EXPECT_FALSE(controller.RendererDidNavigate(params, &details)); | |
2955 | |
2956 // The notification should have updated the last committed one, and not | |
2957 // the pending load. | |
2958 EXPECT_EQ(url1, controller.GetLastCommittedEntry()->GetURL()); | |
2959 | |
2960 // The active entry should be unchanged by the subframe load. | |
2961 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL()); | |
2962 } | |
2963 | |
2964 // Test CopyStateFrom with 2 urls, the first selected and nothing in the target. | |
2965 TEST_F(NavigationControllerTest, CopyStateFrom) { | |
2966 NavigationControllerImpl& controller = controller_impl(); | |
2967 const GURL url1("http://foo1"); | |
2968 const GURL url2("http://foo2"); | |
2969 | |
2970 NavigateAndCommit(url1); | |
2971 NavigateAndCommit(url2); | |
2972 controller.GoBack(); | |
2973 contents()->CommitPendingNavigation(); | |
2974 | |
2975 scoped_ptr<TestWebContents> other_contents( | |
2976 static_cast<TestWebContents*>(CreateTestWebContents())); | |
2977 NavigationControllerImpl& other_controller = other_contents->GetController(); | |
2978 other_controller.CopyStateFrom(controller); | |
2979 | |
2980 // other_controller should now contain 2 urls. | |
2981 ASSERT_EQ(2, other_controller.GetEntryCount()); | |
2982 // We should be looking at the first one. | |
2983 ASSERT_EQ(0, other_controller.GetCurrentEntryIndex()); | |
2984 | |
2985 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL()); | |
2986 EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID()); | |
2987 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL()); | |
2988 // This is a different site than url1, so the IDs start again at 0. | |
2989 EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID()); | |
2990 | |
2991 // The max page ID map should be copied over and updated with the max page ID | |
2992 // from the current tab. | |
2993 SiteInstance* instance1 = | |
2994 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)); | |
2995 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1)); | |
2996 | |
2997 // Ensure the SessionStorageNamespaceMaps are the same size and have | |
2998 // the same partitons loaded. | |
2999 // | |
3000 // TODO(ajwong): We should load a url from a different partition earlier | |
3001 // to make sure this map has more than one entry. | |
3002 const SessionStorageNamespaceMap& session_storage_namespace_map = | |
3003 controller.GetSessionStorageNamespaceMap(); | |
3004 const SessionStorageNamespaceMap& other_session_storage_namespace_map = | |
3005 other_controller.GetSessionStorageNamespaceMap(); | |
3006 EXPECT_EQ(session_storage_namespace_map.size(), | |
3007 other_session_storage_namespace_map.size()); | |
3008 for (SessionStorageNamespaceMap::const_iterator it = | |
3009 session_storage_namespace_map.begin(); | |
3010 it != session_storage_namespace_map.end(); | |
3011 ++it) { | |
3012 SessionStorageNamespaceMap::const_iterator other = | |
3013 other_session_storage_namespace_map.find(it->first); | |
3014 EXPECT_TRUE(other != other_session_storage_namespace_map.end()); | |
3015 } | |
3016 } | |
3017 | |
3018 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest. | |
3019 TEST_F(NavigationControllerTest, CopyStateFromAndPrune) { | |
3020 NavigationControllerImpl& controller = controller_impl(); | |
3021 const GURL url1("http://foo/1"); | |
3022 const GURL url2("http://foo/2"); | |
3023 const GURL url3("http://foo/3"); | |
3024 | |
3025 NavigateAndCommit(url1); | |
3026 NavigateAndCommit(url2); | |
3027 | |
3028 // First two entries should have the same SiteInstance. | |
3029 SiteInstance* instance1 = | |
3030 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)); | |
3031 SiteInstance* instance2 = | |
3032 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1)); | |
3033 EXPECT_EQ(instance1, instance2); | |
3034 EXPECT_EQ(0, controller.GetEntryAtIndex(0)->GetPageID()); | |
3035 EXPECT_EQ(1, controller.GetEntryAtIndex(1)->GetPageID()); | |
3036 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1)); | |
3037 | |
3038 scoped_ptr<TestWebContents> other_contents( | |
3039 static_cast<TestWebContents*>(CreateTestWebContents())); | |
3040 NavigationControllerImpl& other_controller = other_contents->GetController(); | |
3041 other_contents->NavigateAndCommit(url3); | |
3042 other_contents->ExpectSetHistoryLengthAndPrune( | |
3043 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2, | |
3044 other_controller.GetEntryAtIndex(0)->GetPageID()); | |
3045 other_controller.CopyStateFromAndPrune(&controller); | |
3046 | |
3047 // other_controller should now contain the 3 urls: url1, url2 and url3. | |
3048 | |
3049 ASSERT_EQ(3, other_controller.GetEntryCount()); | |
3050 | |
3051 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex()); | |
3052 | |
3053 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL()); | |
3054 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL()); | |
3055 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL()); | |
3056 EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID()); | |
3057 EXPECT_EQ(1, other_controller.GetEntryAtIndex(1)->GetPageID()); | |
3058 EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID()); | |
3059 | |
3060 // A new SiteInstance should be used for the new tab. | |
3061 SiteInstance* instance3 = | |
3062 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2)); | |
3063 EXPECT_NE(instance3, instance1); | |
3064 | |
3065 // The max page ID map should be copied over and updated with the max page ID | |
3066 // from the current tab. | |
3067 EXPECT_EQ(1, other_contents->GetMaxPageIDForSiteInstance(instance1)); | |
3068 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance3)); | |
3069 } | |
3070 | |
3071 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry in | |
3072 // the target. | |
3073 TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) { | |
3074 NavigationControllerImpl& controller = controller_impl(); | |
3075 const GURL url1("http://foo1"); | |
3076 const GURL url2("http://foo2"); | |
3077 const GURL url3("http://foo3"); | |
3078 | |
3079 NavigateAndCommit(url1); | |
3080 NavigateAndCommit(url2); | |
3081 controller.GoBack(); | |
3082 contents()->CommitPendingNavigation(); | |
3083 | |
3084 scoped_ptr<TestWebContents> other_contents( | |
3085 static_cast<TestWebContents*>(CreateTestWebContents())); | |
3086 NavigationControllerImpl& other_controller = other_contents->GetController(); | |
3087 other_contents->NavigateAndCommit(url3); | |
3088 other_contents->ExpectSetHistoryLengthAndPrune( | |
3089 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1, | |
3090 other_controller.GetEntryAtIndex(0)->GetPageID()); | |
3091 other_controller.CopyStateFromAndPrune(&controller); | |
3092 | |
3093 // other_controller should now contain: url1, url3 | |
3094 | |
3095 ASSERT_EQ(2, other_controller.GetEntryCount()); | |
3096 ASSERT_EQ(1, other_controller.GetCurrentEntryIndex()); | |
3097 | |
3098 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL()); | |
3099 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL()); | |
3100 EXPECT_EQ(0, other_controller.GetEntryAtIndex(1)->GetPageID()); | |
3101 | |
3102 // The max page ID map should be copied over and updated with the max page ID | |
3103 // from the current tab. | |
3104 SiteInstance* instance1 = | |
3105 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1)); | |
3106 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1)); | |
3107 } | |
3108 | |
3109 // Test CopyStateFromAndPrune with 2 urls, the last selected and 2 entries in | |
3110 // the target. | |
3111 TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) { | |
3112 NavigationControllerImpl& controller = controller_impl(); | |
3113 const GURL url1("http://foo1"); | |
3114 const GURL url2("http://foo2"); | |
3115 const GURL url3("http://foo3"); | |
3116 const GURL url4("http://foo4"); | |
3117 | |
3118 NavigateAndCommit(url1); | |
3119 NavigateAndCommit(url2); | |
3120 | |
3121 scoped_ptr<TestWebContents> other_contents( | |
3122 static_cast<TestWebContents*>(CreateTestWebContents())); | |
3123 NavigationControllerImpl& other_controller = other_contents->GetController(); | |
3124 other_contents->NavigateAndCommit(url3); | |
3125 other_contents->NavigateAndCommit(url4); | |
3126 other_contents->ExpectSetHistoryLengthAndPrune( | |
3127 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1)), 2, | |
3128 other_controller.GetEntryAtIndex(0)->GetPageID()); | |
3129 other_controller.CopyStateFromAndPrune(&controller); | |
3130 | |
3131 // other_controller should now contain: url1, url2, url4 | |
3132 | |
3133 ASSERT_EQ(3, other_controller.GetEntryCount()); | |
3134 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex()); | |
3135 | |
3136 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL()); | |
3137 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL()); | |
3138 EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL()); | |
3139 | |
3140 // The max page ID map should be copied over and updated with the max page ID | |
3141 // from the current tab. | |
3142 SiteInstance* instance1 = | |
3143 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2)); | |
3144 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1)); | |
3145 } | |
3146 | |
3147 // Test CopyStateFromAndPrune with 2 urls, 2 entries in the target, with | |
3148 // not the last entry selected in the target. | |
3149 TEST_F(NavigationControllerTest, CopyStateFromAndPruneNotLast) { | |
3150 NavigationControllerImpl& controller = controller_impl(); | |
3151 const GURL url1("http://foo1"); | |
3152 const GURL url2("http://foo2"); | |
3153 const GURL url3("http://foo3"); | |
3154 const GURL url4("http://foo4"); | |
3155 | |
3156 NavigateAndCommit(url1); | |
3157 NavigateAndCommit(url2); | |
3158 | |
3159 scoped_ptr<TestWebContents> other_contents( | |
3160 static_cast<TestWebContents*>(CreateTestWebContents())); | |
3161 NavigationControllerImpl& other_controller = other_contents->GetController(); | |
3162 other_contents->NavigateAndCommit(url3); | |
3163 other_contents->NavigateAndCommit(url4); | |
3164 other_controller.GoBack(); | |
3165 other_contents->CommitPendingNavigation(); | |
3166 other_contents->ExpectSetHistoryLengthAndPrune( | |
3167 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2, | |
3168 other_controller.GetEntryAtIndex(0)->GetPageID()); | |
3169 other_controller.CopyStateFromAndPrune(&controller); | |
3170 | |
3171 // other_controller should now contain: url1, url2, url3 | |
3172 | |
3173 ASSERT_EQ(3, other_controller.GetEntryCount()); | |
3174 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex()); | |
3175 | |
3176 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL()); | |
3177 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL()); | |
3178 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL()); | |
3179 | |
3180 // The max page ID map should be copied over and updated with the max page ID | |
3181 // from the current tab. | |
3182 SiteInstance* instance1 = | |
3183 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2)); | |
3184 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1)); | |
3185 } | |
3186 | |
3187 // Test CopyStateFromAndPrune with 2 urls, the first selected and 1 entry plus | |
3188 // a pending entry in the target. | |
3189 TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending) { | |
3190 NavigationControllerImpl& controller = controller_impl(); | |
3191 const GURL url1("http://foo1"); | |
3192 const GURL url2("http://foo2"); | |
3193 const GURL url3("http://foo3"); | |
3194 const GURL url4("http://foo4"); | |
3195 | |
3196 NavigateAndCommit(url1); | |
3197 NavigateAndCommit(url2); | |
3198 controller.GoBack(); | |
3199 contents()->CommitPendingNavigation(); | |
3200 | |
3201 scoped_ptr<TestWebContents> other_contents( | |
3202 static_cast<TestWebContents*>(CreateTestWebContents())); | |
3203 NavigationControllerImpl& other_controller = other_contents->GetController(); | |
3204 other_contents->NavigateAndCommit(url3); | |
3205 other_controller.LoadURL( | |
3206 url4, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
3207 other_contents->ExpectSetHistoryLengthAndPrune( | |
3208 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1, | |
3209 other_controller.GetEntryAtIndex(0)->GetPageID()); | |
3210 other_controller.CopyStateFromAndPrune(&controller); | |
3211 | |
3212 // other_controller should now contain url1, url3, and a pending entry | |
3213 // for url4. | |
3214 | |
3215 ASSERT_EQ(2, other_controller.GetEntryCount()); | |
3216 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex()); | |
3217 | |
3218 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL()); | |
3219 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL()); | |
3220 | |
3221 // And there should be a pending entry for url4. | |
3222 ASSERT_TRUE(other_controller.GetPendingEntry()); | |
3223 EXPECT_EQ(url4, other_controller.GetPendingEntry()->GetURL()); | |
3224 | |
3225 // The max page ID map should be copied over and updated with the max page ID | |
3226 // from the current tab. | |
3227 SiteInstance* instance1 = | |
3228 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)); | |
3229 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1)); | |
3230 } | |
3231 | |
3232 // Test CopyStateFromAndPrune with 1 url in the source, 1 entry and a pending | |
3233 // client redirect entry (with the same page ID) in the target. This used to | |
3234 // crash because the last committed entry would be pruned but max_page_id | |
3235 // remembered the page ID (http://crbug.com/234809). | |
3236 TEST_F(NavigationControllerTest, CopyStateFromAndPruneTargetPending2) { | |
3237 NavigationControllerImpl& controller = controller_impl(); | |
3238 const GURL url1("http://foo1"); | |
3239 const GURL url2a("http://foo2/a"); | |
3240 const GURL url2b("http://foo2/b"); | |
3241 | |
3242 NavigateAndCommit(url1); | |
3243 | |
3244 scoped_ptr<TestWebContents> other_contents( | |
3245 static_cast<TestWebContents*>(CreateTestWebContents())); | |
3246 NavigationControllerImpl& other_controller = other_contents->GetController(); | |
3247 other_contents->NavigateAndCommit(url2a); | |
3248 // Simulate a client redirect, which has the same page ID as entry 2a. | |
3249 other_controller.LoadURL( | |
3250 url2b, Referrer(), PAGE_TRANSITION_LINK, std::string()); | |
3251 other_controller.GetPendingEntry()->SetPageID( | |
3252 other_controller.GetLastCommittedEntry()->GetPageID()); | |
3253 | |
3254 other_contents->ExpectSetHistoryLengthAndPrune( | |
3255 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 1, | |
3256 other_controller.GetEntryAtIndex(0)->GetPageID()); | |
3257 other_controller.CopyStateFromAndPrune(&controller); | |
3258 | |
3259 // other_controller should now contain url1, url2a, and a pending entry | |
3260 // for url2b. | |
3261 | |
3262 ASSERT_EQ(2, other_controller.GetEntryCount()); | |
3263 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex()); | |
3264 | |
3265 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL()); | |
3266 EXPECT_EQ(url2a, other_controller.GetEntryAtIndex(1)->GetURL()); | |
3267 | |
3268 // And there should be a pending entry for url4. | |
3269 ASSERT_TRUE(other_controller.GetPendingEntry()); | |
3270 EXPECT_EQ(url2b, other_controller.GetPendingEntry()->GetURL()); | |
3271 | |
3272 // Let the pending entry commit. | |
3273 other_contents->CommitPendingNavigation(); | |
3274 | |
3275 // The max page ID map should be copied over and updated with the max page ID | |
3276 // from the current tab. | |
3277 SiteInstance* instance1 = | |
3278 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(1)); | |
3279 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1)); | |
3280 } | |
3281 | |
3282 // Test CopyStateFromAndPrune with 2 urls, a back navigation pending in the | |
3283 // source, and 1 entry in the target. The back pending entry should be ignored. | |
3284 TEST_F(NavigationControllerTest, CopyStateFromAndPruneSourcePending) { | |
3285 NavigationControllerImpl& controller = controller_impl(); | |
3286 const GURL url1("http://foo1"); | |
3287 const GURL url2("http://foo2"); | |
3288 const GURL url3("http://foo3"); | |
3289 | |
3290 NavigateAndCommit(url1); | |
3291 NavigateAndCommit(url2); | |
3292 controller.GoBack(); | |
3293 | |
3294 scoped_ptr<TestWebContents> other_contents( | |
3295 static_cast<TestWebContents*>(CreateTestWebContents())); | |
3296 NavigationControllerImpl& other_controller = other_contents->GetController(); | |
3297 other_contents->NavigateAndCommit(url3); | |
3298 other_contents->ExpectSetHistoryLengthAndPrune( | |
3299 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2, | |
3300 other_controller.GetEntryAtIndex(0)->GetPageID()); | |
3301 other_controller.CopyStateFromAndPrune(&controller); | |
3302 | |
3303 // other_controller should now contain: url1, url2, url3 | |
3304 | |
3305 ASSERT_EQ(3, other_controller.GetEntryCount()); | |
3306 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex()); | |
3307 | |
3308 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL()); | |
3309 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL()); | |
3310 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL()); | |
3311 EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID()); | |
3312 | |
3313 // The max page ID map should be copied over and updated with the max page ID | |
3314 // from the current tab. | |
3315 SiteInstance* instance1 = | |
3316 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2)); | |
3317 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1)); | |
3318 } | |
3319 | |
3320 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest, | |
3321 // when the max entry count is 3. We should prune one entry. | |
3322 TEST_F(NavigationControllerTest, CopyStateFromAndPruneMaxEntries) { | |
3323 NavigationControllerImpl& controller = controller_impl(); | |
3324 size_t original_count = NavigationControllerImpl::max_entry_count(); | |
3325 const int kMaxEntryCount = 3; | |
3326 | |
3327 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount); | |
3328 | |
3329 const GURL url1("http://foo/1"); | |
3330 const GURL url2("http://foo/2"); | |
3331 const GURL url3("http://foo/3"); | |
3332 const GURL url4("http://foo/4"); | |
3333 | |
3334 // Create a PrunedListener to observe prune notifications. | |
3335 PrunedListener listener(&controller); | |
3336 | |
3337 NavigateAndCommit(url1); | |
3338 NavigateAndCommit(url2); | |
3339 NavigateAndCommit(url3); | |
3340 | |
3341 scoped_ptr<TestWebContents> other_contents( | |
3342 static_cast<TestWebContents*>(CreateTestWebContents())); | |
3343 NavigationControllerImpl& other_controller = other_contents->GetController(); | |
3344 other_contents->NavigateAndCommit(url4); | |
3345 other_contents->ExpectSetHistoryLengthAndPrune( | |
3346 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2, | |
3347 other_controller.GetEntryAtIndex(0)->GetPageID()); | |
3348 other_controller.CopyStateFromAndPrune(&controller); | |
3349 | |
3350 // We should have received a pruned notification. | |
3351 EXPECT_EQ(1, listener.notification_count_); | |
3352 EXPECT_TRUE(listener.details_.from_front); | |
3353 EXPECT_EQ(1, listener.details_.count); | |
3354 | |
3355 // other_controller should now contain only 3 urls: url2, url3 and url4. | |
3356 | |
3357 ASSERT_EQ(3, other_controller.GetEntryCount()); | |
3358 | |
3359 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex()); | |
3360 | |
3361 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(0)->GetURL()); | |
3362 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL()); | |
3363 EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL()); | |
3364 EXPECT_EQ(1, other_controller.GetEntryAtIndex(0)->GetPageID()); | |
3365 EXPECT_EQ(2, other_controller.GetEntryAtIndex(1)->GetPageID()); | |
3366 EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID()); | |
3367 | |
3368 NavigationControllerImpl::set_max_entry_count_for_testing(original_count); | |
3369 } | |
3370 | |
3371 // Tests that navigations initiated from the page (with the history object) | |
3372 // work as expected without navigation entries. | |
3373 TEST_F(NavigationControllerTest, HistoryNavigate) { | |
3374 NavigationControllerImpl& controller = controller_impl(); | |
3375 const GURL url1("http://foo/1"); | |
3376 const GURL url2("http://foo/2"); | |
3377 const GURL url3("http://foo/3"); | |
3378 | |
3379 NavigateAndCommit(url1); | |
3380 NavigateAndCommit(url2); | |
3381 NavigateAndCommit(url3); | |
3382 controller.GoBack(); | |
3383 contents()->CommitPendingNavigation(); | |
3384 | |
3385 // Simulate the page calling history.back(), it should not create a pending | |
3386 // entry. | |
3387 contents()->OnGoToEntryAtOffset(-1); | |
3388 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
3389 // The actual cross-navigation is suspended until the current RVH tells us | |
3390 // it unloaded, simulate that. | |
3391 contents()->ProceedWithCrossSiteNavigation(); | |
3392 // Also make sure we told the page to navigate. | |
3393 const IPC::Message* message = | |
3394 process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID); | |
3395 ASSERT_TRUE(message != NULL); | |
3396 Tuple1<ViewMsg_Navigate_Params> nav_params; | |
3397 ViewMsg_Navigate::Read(message, &nav_params); | |
3398 EXPECT_EQ(url1, nav_params.a.url); | |
3399 process()->sink().ClearMessages(); | |
3400 | |
3401 // Now test history.forward() | |
3402 contents()->OnGoToEntryAtOffset(1); | |
3403 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
3404 // The actual cross-navigation is suspended until the current RVH tells us | |
3405 // it unloaded, simulate that. | |
3406 contents()->ProceedWithCrossSiteNavigation(); | |
3407 message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID); | |
3408 ASSERT_TRUE(message != NULL); | |
3409 ViewMsg_Navigate::Read(message, &nav_params); | |
3410 EXPECT_EQ(url3, nav_params.a.url); | |
3411 process()->sink().ClearMessages(); | |
3412 | |
3413 // Make sure an extravagant history.go() doesn't break. | |
3414 contents()->OnGoToEntryAtOffset(120); // Out of bounds. | |
3415 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
3416 message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID); | |
3417 EXPECT_TRUE(message == NULL); | |
3418 } | |
3419 | |
3420 // Test call to PruneAllButVisible for the only entry. | |
3421 TEST_F(NavigationControllerTest, PruneAllButVisibleForSingle) { | |
3422 NavigationControllerImpl& controller = controller_impl(); | |
3423 const GURL url1("http://foo1"); | |
3424 NavigateAndCommit(url1); | |
3425 | |
3426 contents()->ExpectSetHistoryLengthAndPrune( | |
3427 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0, | |
3428 controller.GetEntryAtIndex(0)->GetPageID()); | |
3429 | |
3430 controller.PruneAllButVisible(); | |
3431 | |
3432 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
3433 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1); | |
3434 } | |
3435 | |
3436 // Test call to PruneAllButVisible for first entry. | |
3437 TEST_F(NavigationControllerTest, PruneAllButVisibleForFirst) { | |
3438 NavigationControllerImpl& controller = controller_impl(); | |
3439 const GURL url1("http://foo/1"); | |
3440 const GURL url2("http://foo/2"); | |
3441 const GURL url3("http://foo/3"); | |
3442 | |
3443 NavigateAndCommit(url1); | |
3444 NavigateAndCommit(url2); | |
3445 NavigateAndCommit(url3); | |
3446 controller.GoBack(); | |
3447 controller.GoBack(); | |
3448 contents()->CommitPendingNavigation(); | |
3449 | |
3450 contents()->ExpectSetHistoryLengthAndPrune( | |
3451 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0)), 0, | |
3452 controller.GetEntryAtIndex(0)->GetPageID()); | |
3453 | |
3454 controller.PruneAllButVisible(); | |
3455 | |
3456 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
3457 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1); | |
3458 } | |
3459 | |
3460 // Test call to PruneAllButVisible for intermediate entry. | |
3461 TEST_F(NavigationControllerTest, PruneAllButVisibleForIntermediate) { | |
3462 NavigationControllerImpl& controller = controller_impl(); | |
3463 const GURL url1("http://foo/1"); | |
3464 const GURL url2("http://foo/2"); | |
3465 const GURL url3("http://foo/3"); | |
3466 | |
3467 NavigateAndCommit(url1); | |
3468 NavigateAndCommit(url2); | |
3469 NavigateAndCommit(url3); | |
3470 controller.GoBack(); | |
3471 contents()->CommitPendingNavigation(); | |
3472 | |
3473 contents()->ExpectSetHistoryLengthAndPrune( | |
3474 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1)), 0, | |
3475 controller.GetEntryAtIndex(1)->GetPageID()); | |
3476 | |
3477 controller.PruneAllButVisible(); | |
3478 | |
3479 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
3480 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url2); | |
3481 } | |
3482 | |
3483 // Test call to PruneAllButVisible for a pending entry that is not yet in the | |
3484 // list of entries. | |
3485 TEST_F(NavigationControllerTest, PruneAllButVisibleForPendingNotInList) { | |
3486 NavigationControllerImpl& controller = controller_impl(); | |
3487 const GURL url1("http://foo/1"); | |
3488 const GURL url2("http://foo/2"); | |
3489 const GURL url3("http://foo/3"); | |
3490 | |
3491 NavigateAndCommit(url1); | |
3492 NavigateAndCommit(url2); | |
3493 | |
3494 // Create a pending entry that is not in the entry list. | |
3495 controller.LoadURL( | |
3496 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
3497 EXPECT_TRUE(controller.GetPendingEntry()); | |
3498 EXPECT_EQ(2, controller.GetEntryCount()); | |
3499 | |
3500 contents()->ExpectSetHistoryLengthAndPrune( | |
3501 NULL, 0, controller.GetPendingEntry()->GetPageID()); | |
3502 controller.PruneAllButVisible(); | |
3503 | |
3504 // We should only have the last committed and pending entries at this point, | |
3505 // and the pending entry should still not be in the entry list. | |
3506 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); | |
3507 EXPECT_EQ(url2, controller.GetEntryAtIndex(0)->GetURL()); | |
3508 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
3509 EXPECT_TRUE(controller.GetPendingEntry()); | |
3510 EXPECT_EQ(1, controller.GetEntryCount()); | |
3511 | |
3512 // Try to commit the pending entry. | |
3513 test_rvh()->SendNavigate(2, url3); | |
3514 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
3515 EXPECT_FALSE(controller.GetPendingEntry()); | |
3516 EXPECT_EQ(2, controller.GetEntryCount()); | |
3517 EXPECT_EQ(url3, controller.GetEntryAtIndex(1)->GetURL()); | |
3518 } | |
3519 | |
3520 // Test to ensure that when we do a history navigation back to the current | |
3521 // committed page (e.g., going forward to a slow-loading page, then pressing | |
3522 // the back button), we just stop the navigation to prevent the throbber from | |
3523 // running continuously. Otherwise, the RenderViewHost forces the throbber to | |
3524 // start, but WebKit essentially ignores the navigation and never sends a | |
3525 // message to stop the throbber. | |
3526 TEST_F(NavigationControllerTest, StopOnHistoryNavigationToCurrentPage) { | |
3527 NavigationControllerImpl& controller = controller_impl(); | |
3528 const GURL url0("http://foo/0"); | |
3529 const GURL url1("http://foo/1"); | |
3530 | |
3531 NavigateAndCommit(url0); | |
3532 NavigateAndCommit(url1); | |
3533 | |
3534 // Go back to the original page, then forward to the slow page, then back | |
3535 controller.GoBack(); | |
3536 contents()->CommitPendingNavigation(); | |
3537 | |
3538 controller.GoForward(); | |
3539 EXPECT_EQ(1, controller.GetPendingEntryIndex()); | |
3540 | |
3541 controller.GoBack(); | |
3542 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
3543 } | |
3544 | |
3545 TEST_F(NavigationControllerTest, IsInitialNavigation) { | |
3546 NavigationControllerImpl& controller = controller_impl(); | |
3547 TestNotificationTracker notifications; | |
3548 RegisterForAllNavNotifications(¬ifications, &controller); | |
3549 | |
3550 // Initial state. | |
3551 EXPECT_TRUE(controller.IsInitialNavigation()); | |
3552 | |
3553 // After commit, it stays false. | |
3554 const GURL url1("http://foo1"); | |
3555 test_rvh()->SendNavigate(0, url1); | |
3556 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
3557 navigation_entry_committed_counter_ = 0; | |
3558 EXPECT_FALSE(controller.IsInitialNavigation()); | |
3559 | |
3560 // After starting a new navigation, it stays false. | |
3561 const GURL url2("http://foo2"); | |
3562 controller.LoadURL( | |
3563 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); | |
3564 } | |
3565 | |
3566 // Check that the favicon is not reused across a client redirect. | |
3567 // (crbug.com/28515) | |
3568 TEST_F(NavigationControllerTest, ClearFaviconOnRedirect) { | |
3569 const GURL kPageWithFavicon("http://withfavicon.html"); | |
3570 const GURL kPageWithoutFavicon("http://withoutfavicon.html"); | |
3571 const GURL kIconURL("http://withfavicon.ico"); | |
3572 const gfx::Image kDefaultFavicon = FaviconStatus().image; | |
3573 | |
3574 NavigationControllerImpl& controller = controller_impl(); | |
3575 TestNotificationTracker notifications; | |
3576 RegisterForAllNavNotifications(¬ifications, &controller); | |
3577 | |
3578 test_rvh()->SendNavigate(0, kPageWithFavicon); | |
3579 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
3580 navigation_entry_committed_counter_ = 0; | |
3581 | |
3582 NavigationEntry* entry = controller.GetLastCommittedEntry(); | |
3583 EXPECT_TRUE(entry); | |
3584 EXPECT_EQ(kPageWithFavicon, entry->GetURL()); | |
3585 | |
3586 // Simulate Chromium having set the favicon for |kPageWithFavicon|. | |
3587 content::FaviconStatus& favicon_status = entry->GetFavicon(); | |
3588 favicon_status.image = CreateImage(SK_ColorWHITE); | |
3589 favicon_status.url = kIconURL; | |
3590 favicon_status.valid = true; | |
3591 EXPECT_FALSE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image)); | |
3592 | |
3593 test_rvh()->SendNavigateWithTransition( | |
3594 0, // same page ID. | |
3595 kPageWithoutFavicon, | |
3596 PAGE_TRANSITION_CLIENT_REDIRECT); | |
3597 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
3598 navigation_entry_committed_counter_ = 0; | |
3599 | |
3600 entry = controller.GetLastCommittedEntry(); | |
3601 EXPECT_TRUE(entry); | |
3602 EXPECT_EQ(kPageWithoutFavicon, entry->GetURL()); | |
3603 | |
3604 EXPECT_TRUE(DoImagesMatch(kDefaultFavicon, entry->GetFavicon().image)); | |
3605 } | |
3606 | |
3607 // Check that the favicon is not cleared for NavigationEntries which were | |
3608 // previously navigated to. | |
3609 TEST_F(NavigationControllerTest, BackNavigationDoesNotClearFavicon) { | |
3610 const GURL kUrl1("http://www.a.com/1"); | |
3611 const GURL kUrl2("http://www.a.com/2"); | |
3612 const GURL kIconURL("http://www.a.com/1/favicon.ico"); | |
3613 | |
3614 NavigationControllerImpl& controller = controller_impl(); | |
3615 TestNotificationTracker notifications; | |
3616 RegisterForAllNavNotifications(¬ifications, &controller); | |
3617 | |
3618 test_rvh()->SendNavigate(0, kUrl1); | |
3619 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
3620 navigation_entry_committed_counter_ = 0; | |
3621 | |
3622 // Simulate Chromium having set the favicon for |kUrl1|. | |
3623 gfx::Image favicon_image = CreateImage(SK_ColorWHITE); | |
3624 content::NavigationEntry* entry = controller.GetLastCommittedEntry(); | |
3625 EXPECT_TRUE(entry); | |
3626 content::FaviconStatus& favicon_status = entry->GetFavicon(); | |
3627 favicon_status.image = favicon_image; | |
3628 favicon_status.url = kIconURL; | |
3629 favicon_status.valid = true; | |
3630 | |
3631 // Navigate to another page and go back to the original page. | |
3632 test_rvh()->SendNavigate(1, kUrl2); | |
3633 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
3634 navigation_entry_committed_counter_ = 0; | |
3635 test_rvh()->SendNavigateWithTransition( | |
3636 0, | |
3637 kUrl1, | |
3638 PAGE_TRANSITION_FORWARD_BACK); | |
3639 EXPECT_EQ(1U, navigation_entry_committed_counter_); | |
3640 navigation_entry_committed_counter_ = 0; | |
3641 | |
3642 // Verify that the favicon for the page at |kUrl1| was not cleared. | |
3643 entry = controller.GetEntryAtIndex(0); | |
3644 EXPECT_TRUE(entry); | |
3645 EXPECT_EQ(kUrl1, entry->GetURL()); | |
3646 EXPECT_TRUE(DoImagesMatch(favicon_image, entry->GetFavicon().image)); | |
3647 } | |
3648 | |
3649 // The test crashes on android: http://crbug.com/170449 | |
3650 #if defined(OS_ANDROID) | |
3651 #define MAYBE_PurgeScreenshot DISABLED_PurgeScreenshot | |
3652 #else | |
3653 #define MAYBE_PurgeScreenshot PurgeScreenshot | |
3654 #endif | |
3655 // Tests that screenshot are purged correctly. | |
3656 TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) { | |
3657 NavigationControllerImpl& controller = controller_impl(); | |
3658 | |
3659 NavigationEntryImpl* entry; | |
3660 | |
3661 // Navigate enough times to make sure that some screenshots are purged. | |
3662 for (int i = 0; i < 12; ++i) { | |
3663 const GURL url(base::StringPrintf("http://foo%d/", i)); | |
3664 NavigateAndCommit(url); | |
3665 EXPECT_EQ(i, controller.GetCurrentEntryIndex()); | |
3666 } | |
3667 | |
3668 MockScreenshotManager* screenshot_manager = | |
3669 new MockScreenshotManager(&controller); | |
3670 controller.SetScreenshotManager(screenshot_manager); | |
3671 for (int i = 0; i < controller.GetEntryCount(); ++i) { | |
3672 entry = NavigationEntryImpl::FromNavigationEntry( | |
3673 controller.GetEntryAtIndex(i)); | |
3674 screenshot_manager->TakeScreenshotFor(entry); | |
3675 EXPECT_TRUE(entry->screenshot().get()); | |
3676 } | |
3677 | |
3678 NavigateAndCommit(GURL("https://foo/")); | |
3679 EXPECT_EQ(13, controller.GetEntryCount()); | |
3680 entry = NavigationEntryImpl::FromNavigationEntry( | |
3681 controller.GetEntryAtIndex(11)); | |
3682 screenshot_manager->TakeScreenshotFor(entry); | |
3683 | |
3684 for (int i = 0; i < 2; ++i) { | |
3685 entry = NavigationEntryImpl::FromNavigationEntry( | |
3686 controller.GetEntryAtIndex(i)); | |
3687 EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i | |
3688 << " not purged"; | |
3689 } | |
3690 | |
3691 for (int i = 2; i < controller.GetEntryCount() - 1; ++i) { | |
3692 entry = NavigationEntryImpl::FromNavigationEntry( | |
3693 controller.GetEntryAtIndex(i)); | |
3694 EXPECT_TRUE(entry->screenshot().get()) << "Screenshot not found for " << i; | |
3695 } | |
3696 | |
3697 // Navigate to index 5 and then try to assign screenshot to all entries. | |
3698 controller.GoToIndex(5); | |
3699 contents()->CommitPendingNavigation(); | |
3700 EXPECT_EQ(5, controller.GetCurrentEntryIndex()); | |
3701 for (int i = 0; i < controller.GetEntryCount() - 1; ++i) { | |
3702 entry = NavigationEntryImpl::FromNavigationEntry( | |
3703 controller.GetEntryAtIndex(i)); | |
3704 screenshot_manager->TakeScreenshotFor(entry); | |
3705 } | |
3706 | |
3707 for (int i = 10; i <= 12; ++i) { | |
3708 entry = NavigationEntryImpl::FromNavigationEntry( | |
3709 controller.GetEntryAtIndex(i)); | |
3710 EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i | |
3711 << " not purged"; | |
3712 screenshot_manager->TakeScreenshotFor(entry); | |
3713 } | |
3714 | |
3715 // Navigate to index 7 and assign screenshot to all entries. | |
3716 controller.GoToIndex(7); | |
3717 contents()->CommitPendingNavigation(); | |
3718 EXPECT_EQ(7, controller.GetCurrentEntryIndex()); | |
3719 for (int i = 0; i < controller.GetEntryCount() - 1; ++i) { | |
3720 entry = NavigationEntryImpl::FromNavigationEntry( | |
3721 controller.GetEntryAtIndex(i)); | |
3722 screenshot_manager->TakeScreenshotFor(entry); | |
3723 } | |
3724 | |
3725 for (int i = 0; i < 2; ++i) { | |
3726 entry = NavigationEntryImpl::FromNavigationEntry( | |
3727 controller.GetEntryAtIndex(i)); | |
3728 EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i | |
3729 << " not purged"; | |
3730 } | |
3731 | |
3732 // Clear all screenshots. | |
3733 EXPECT_EQ(13, controller.GetEntryCount()); | |
3734 EXPECT_EQ(10, screenshot_manager->GetScreenshotCount()); | |
3735 controller.ClearAllScreenshots(); | |
3736 EXPECT_EQ(0, screenshot_manager->GetScreenshotCount()); | |
3737 for (int i = 0; i < controller.GetEntryCount(); ++i) { | |
3738 entry = NavigationEntryImpl::FromNavigationEntry( | |
3739 controller.GetEntryAtIndex(i)); | |
3740 EXPECT_FALSE(entry->screenshot().get()) << "Screenshot " << i | |
3741 << " not cleared"; | |
3742 } | |
3743 } | |
3744 | |
3745 // Test that the navigation controller clears its session history when a | |
3746 // navigation commits with the clear history list flag set. | |
3747 TEST_F(NavigationControllerTest, ClearHistoryList) { | |
3748 const GURL url1("http://foo1"); | |
3749 const GURL url2("http://foo2"); | |
3750 const GURL url3("http://foo3"); | |
3751 const GURL url4("http://foo4"); | |
3752 | |
3753 NavigationControllerImpl& controller = controller_impl(); | |
3754 | |
3755 // Create a session history with three entries, second entry is active. | |
3756 NavigateAndCommit(url1); | |
3757 NavigateAndCommit(url2); | |
3758 NavigateAndCommit(url3); | |
3759 controller.GoBack(); | |
3760 contents()->CommitPendingNavigation(); | |
3761 EXPECT_EQ(3, controller.GetEntryCount()); | |
3762 EXPECT_EQ(1, controller.GetCurrentEntryIndex()); | |
3763 | |
3764 // Create a new pending navigation, and indicate that the session history | |
3765 // should be cleared. | |
3766 NavigationController::LoadURLParams params(url4); | |
3767 params.should_clear_history_list = true; | |
3768 controller.LoadURLWithParams(params); | |
3769 | |
3770 // Verify that the pending entry correctly indicates that the session history | |
3771 // should be cleared. | |
3772 NavigationEntryImpl* entry = | |
3773 NavigationEntryImpl::FromNavigationEntry( | |
3774 controller.GetPendingEntry()); | |
3775 ASSERT_TRUE(entry); | |
3776 EXPECT_TRUE(entry->should_clear_history_list()); | |
3777 | |
3778 // Assume that the RV correctly cleared its history and commit the navigation. | |
3779 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost())-> | |
3780 set_simulate_history_list_was_cleared(true); | |
3781 contents()->CommitPendingNavigation(); | |
3782 | |
3783 // Verify that the NavigationController's session history was correctly | |
3784 // cleared. | |
3785 EXPECT_EQ(1, controller.GetEntryCount()); | |
3786 EXPECT_EQ(0, controller.GetCurrentEntryIndex()); | |
3787 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); | |
3788 EXPECT_EQ(-1, controller.GetPendingEntryIndex()); | |
3789 EXPECT_FALSE(controller.CanGoBack()); | |
3790 EXPECT_FALSE(controller.CanGoForward()); | |
3791 EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL()); | |
3792 } | |
3793 | |
3794 } // namespace content | |
OLD | NEW |