Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(121)

Side by Side Diff: content/browser/tab_contents/navigation_controller_impl_unittest.cc

Issue 9960071: TabContents -> WebContentsImpl, part 3. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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/file_util.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/path_service.h"
8 #include "base/stl_util.h"
9 #include "base/string_util.h"
10 #include "base/utf_string_conversions.h"
11 // These are only used for commented out tests. If someone wants to enable
12 // them, they should be moved to chrome first.
13 // #include "chrome/browser/history/history.h"
14 // #include "chrome/browser/profiles/profile_manager.h"
15 // #include "chrome/browser/sessions/session_service.h"
16 // #include "chrome/browser/sessions/session_service_factory.h"
17 // #include "chrome/browser/sessions/session_service_test_helper.h"
18 // #include "chrome/browser/sessions/session_types.h"
19 #include "content/browser/renderer_host/test_render_view_host.h"
20 #include "content/browser/site_instance_impl.h"
21 #include "content/browser/tab_contents/navigation_controller_impl.h"
22 #include "content/browser/tab_contents/navigation_entry_impl.h"
23 #include "content/browser/tab_contents/tab_contents.h"
24 #include "content/browser/tab_contents/test_web_contents.h"
25 #include "content/common/view_messages.h"
26 #include "content/public/browser/navigation_details.h"
27 #include "content/public/browser/notification_registrar.h"
28 #include "content/public/browser/notification_types.h"
29 #include "content/public/browser/web_contents_delegate.h"
30 #include "content/test/mock_render_process_host.h"
31 #include "content/test/test_browser_context.h"
32 #include "content/test/test_notification_tracker.h"
33 #include "net/base/net_util.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35 #include "webkit/glue/webkit_glue.h"
36
37 using base::Time;
38 using content::NavigationController;
39 using content::NavigationEntry;
40 using content::NavigationEntryImpl;
41 using content::RenderViewHostImplTestHarness;
42 using content::SiteInstance;
43 using content::TestRenderViewHost;
44 using content::TestWebContents;
45 using content::WebContents;
46
47 // NavigationControllerTest ----------------------------------------------------
48
49 class NavigationControllerTest : public RenderViewHostImplTestHarness {
50 public:
51 NavigationControllerTest() {}
52
53 NavigationControllerImpl& controller_impl() {
54 return static_cast<NavigationControllerImpl&>(controller());
55 }
56 };
57
58 void RegisterForAllNavNotifications(TestNotificationTracker* tracker,
59 NavigationController* controller) {
60 tracker->ListenFor(content::NOTIFICATION_NAV_ENTRY_COMMITTED,
61 content::Source<NavigationController>(
62 controller));
63 tracker->ListenFor(content::NOTIFICATION_NAV_LIST_PRUNED,
64 content::Source<NavigationController>(
65 controller));
66 tracker->ListenFor(content::NOTIFICATION_NAV_ENTRY_CHANGED,
67 content::Source<NavigationController>(
68 controller));
69 }
70
71 SiteInstance* GetSiteInstanceFromEntry(NavigationEntry* entry) {
72 return NavigationEntryImpl::FromNavigationEntry(entry)->site_instance();
73 }
74
75 class TestWebContentsDelegate : public content::WebContentsDelegate {
76 public:
77 explicit TestWebContentsDelegate() :
78 navigation_state_change_count_(0) {}
79
80 int navigation_state_change_count() {
81 return navigation_state_change_count_;
82 }
83
84 // Keep track of whether the tab has notified us of a navigation state change.
85 virtual void NavigationStateChanged(const WebContents* source,
86 unsigned changed_flags) {
87 navigation_state_change_count_++;
88 }
89
90 private:
91 // The number of times NavigationStateChanged has been called.
92 int navigation_state_change_count_;
93 };
94
95 // -----------------------------------------------------------------------------
96
97 TEST_F(NavigationControllerTest, Defaults) {
98 NavigationControllerImpl& controller = controller_impl();
99
100 EXPECT_FALSE(controller.GetPendingEntry());
101 EXPECT_FALSE(controller.GetLastCommittedEntry());
102 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
103 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
104 EXPECT_EQ(controller.GetEntryCount(), 0);
105 EXPECT_FALSE(controller.CanGoBack());
106 EXPECT_FALSE(controller.CanGoForward());
107 }
108
109 TEST_F(NavigationControllerTest, LoadURL) {
110 NavigationControllerImpl& controller = controller_impl();
111 TestNotificationTracker notifications;
112 RegisterForAllNavNotifications(&notifications, &controller);
113
114 const GURL url1("http://foo1");
115 const GURL url2("http://foo2");
116
117 controller.LoadURL(
118 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
119 // Creating a pending notification should not have issued any of the
120 // notifications we're listening for.
121 EXPECT_EQ(0U, notifications.size());
122
123 // The load should now be pending.
124 EXPECT_EQ(controller.GetEntryCount(), 0);
125 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), -1);
126 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
127 EXPECT_FALSE(controller.GetLastCommittedEntry());
128 EXPECT_TRUE(controller.GetPendingEntry());
129 EXPECT_FALSE(controller.CanGoBack());
130 EXPECT_FALSE(controller.CanGoForward());
131 EXPECT_EQ(contents()->GetMaxPageID(), -1);
132
133 // We should have gotten no notifications from the preceeding checks.
134 EXPECT_EQ(0U, notifications.size());
135
136 test_rvh()->SendNavigate(0, url1);
137 EXPECT_TRUE(notifications.Check1AndReset(
138 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
139
140 // The load should now be committed.
141 EXPECT_EQ(controller.GetEntryCount(), 1);
142 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
143 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
144 EXPECT_TRUE(controller.GetLastCommittedEntry());
145 EXPECT_FALSE(controller.GetPendingEntry());
146 EXPECT_FALSE(controller.CanGoBack());
147 EXPECT_FALSE(controller.CanGoForward());
148 EXPECT_EQ(contents()->GetMaxPageID(), 0);
149
150 // Load another...
151 controller.LoadURL(
152 url2, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
153
154 // The load should now be pending.
155 EXPECT_EQ(controller.GetEntryCount(), 1);
156 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
157 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
158 EXPECT_TRUE(controller.GetLastCommittedEntry());
159 EXPECT_TRUE(controller.GetPendingEntry());
160 // TODO(darin): maybe this should really be true?
161 EXPECT_FALSE(controller.CanGoBack());
162 EXPECT_FALSE(controller.CanGoForward());
163 EXPECT_EQ(contents()->GetMaxPageID(), 0);
164
165 // Simulate the beforeunload ack for the cross-site transition, and then the
166 // commit.
167 test_rvh()->SendShouldCloseACK(true);
168 static_cast<TestRenderViewHost*>(
169 contents()->GetPendingRenderViewHost())->SendNavigate(1, url2);
170 EXPECT_TRUE(notifications.Check1AndReset(
171 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
172
173 // The load should now be committed.
174 EXPECT_EQ(controller.GetEntryCount(), 2);
175 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
176 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
177 EXPECT_TRUE(controller.GetLastCommittedEntry());
178 EXPECT_FALSE(controller.GetPendingEntry());
179 EXPECT_TRUE(controller.CanGoBack());
180 EXPECT_FALSE(controller.CanGoForward());
181 EXPECT_EQ(contents()->GetMaxPageID(), 1);
182 }
183
184 // Tests what happens when the same page is loaded again. Should not create a
185 // new session history entry. This is what happens when you press enter in the
186 // URL bar to reload: a pending entry is created and then it is discarded when
187 // the load commits (because WebCore didn't actually make a new entry).
188 TEST_F(NavigationControllerTest, LoadURL_SamePage) {
189 NavigationControllerImpl& controller = controller_impl();
190 TestNotificationTracker notifications;
191 RegisterForAllNavNotifications(&notifications, &controller);
192
193 const GURL url1("http://foo1");
194
195 controller.LoadURL(
196 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
197 EXPECT_EQ(0U, notifications.size());
198 test_rvh()->SendNavigate(0, url1);
199 EXPECT_TRUE(notifications.Check1AndReset(
200 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
201
202 controller.LoadURL(
203 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
204 EXPECT_EQ(0U, notifications.size());
205 test_rvh()->SendNavigate(0, url1);
206 EXPECT_TRUE(notifications.Check1AndReset(
207 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
208
209 // We should not have produced a new session history entry.
210 EXPECT_EQ(controller.GetEntryCount(), 1);
211 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
212 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
213 EXPECT_TRUE(controller.GetLastCommittedEntry());
214 EXPECT_FALSE(controller.GetPendingEntry());
215 EXPECT_FALSE(controller.CanGoBack());
216 EXPECT_FALSE(controller.CanGoForward());
217 }
218
219 // Tests loading a URL but discarding it before the load commits.
220 TEST_F(NavigationControllerTest, LoadURL_Discarded) {
221 NavigationControllerImpl& controller = controller_impl();
222 TestNotificationTracker notifications;
223 RegisterForAllNavNotifications(&notifications, &controller);
224
225 const GURL url1("http://foo1");
226 const GURL url2("http://foo2");
227
228 controller.LoadURL(
229 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
230 EXPECT_EQ(0U, notifications.size());
231 test_rvh()->SendNavigate(0, url1);
232 EXPECT_TRUE(notifications.Check1AndReset(
233 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
234
235 controller.LoadURL(
236 url2, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
237 controller.DiscardNonCommittedEntries();
238 EXPECT_EQ(0U, notifications.size());
239
240 // Should not have produced a new session history entry.
241 EXPECT_EQ(controller.GetEntryCount(), 1);
242 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
243 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
244 EXPECT_TRUE(controller.GetLastCommittedEntry());
245 EXPECT_FALSE(controller.GetPendingEntry());
246 EXPECT_FALSE(controller.CanGoBack());
247 EXPECT_FALSE(controller.CanGoForward());
248 }
249
250 // Tests navigations that come in unrequested. This happens when the user
251 // navigates from the web page, and here we test that there is no pending entry.
252 TEST_F(NavigationControllerTest, LoadURL_NoPending) {
253 NavigationControllerImpl& controller = controller_impl();
254 TestNotificationTracker notifications;
255 RegisterForAllNavNotifications(&notifications, &controller);
256
257 // First make an existing committed entry.
258 const GURL kExistingURL1("http://eh");
259 controller.LoadURL(kExistingURL1, content::Referrer(),
260 content::PAGE_TRANSITION_TYPED, std::string());
261 test_rvh()->SendNavigate(0, kExistingURL1);
262 EXPECT_TRUE(notifications.Check1AndReset(
263 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
264
265 // Do a new navigation without making a pending one.
266 const GURL kNewURL("http://see");
267 test_rvh()->SendNavigate(99, kNewURL);
268
269 // There should no longer be any pending entry, and the third navigation we
270 // just made should be committed.
271 EXPECT_TRUE(notifications.Check1AndReset(
272 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
273 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
274 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
275 EXPECT_EQ(kNewURL, controller.GetActiveEntry()->GetURL());
276 }
277
278 // Tests navigating to a new URL when there is a new pending navigation that is
279 // not the one that just loaded. This will happen if the user types in a URL to
280 // somewhere slow, and then navigates the current page before the typed URL
281 // commits.
282 TEST_F(NavigationControllerTest, LoadURL_NewPending) {
283 NavigationControllerImpl& controller = controller_impl();
284 TestNotificationTracker notifications;
285 RegisterForAllNavNotifications(&notifications, &controller);
286
287 // First make an existing committed entry.
288 const GURL kExistingURL1("http://eh");
289 controller.LoadURL(kExistingURL1, content::Referrer(),
290 content::PAGE_TRANSITION_TYPED, std::string());
291 test_rvh()->SendNavigate(0, kExistingURL1);
292 EXPECT_TRUE(notifications.Check1AndReset(
293 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
294
295 // Make a pending entry to somewhere new.
296 const GURL kExistingURL2("http://bee");
297 controller.LoadURL(kExistingURL2, content::Referrer(),
298 content::PAGE_TRANSITION_TYPED, std::string());
299 EXPECT_EQ(0U, notifications.size());
300
301 // After the beforeunload but before it commits, do a new navigation.
302 test_rvh()->SendShouldCloseACK(true);
303 const GURL kNewURL("http://see");
304 static_cast<TestRenderViewHost*>(
305 contents()->GetPendingRenderViewHost())->SendNavigate(3, kNewURL);
306
307 // There should no longer be any pending entry, and the third navigation we
308 // just made should be committed.
309 EXPECT_TRUE(notifications.Check1AndReset(
310 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
311 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
312 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
313 EXPECT_EQ(kNewURL, controller.GetActiveEntry()->GetURL());
314 }
315
316 // Tests navigating to a new URL when there is a pending back/forward
317 // navigation. This will happen if the user hits back, but before that commits,
318 // they navigate somewhere new.
319 TEST_F(NavigationControllerTest, LoadURL_ExistingPending) {
320 NavigationControllerImpl& controller = controller_impl();
321 TestNotificationTracker notifications;
322 RegisterForAllNavNotifications(&notifications, &controller);
323
324 // First make some history.
325 const GURL kExistingURL1("http://foo/eh");
326 controller.LoadURL(kExistingURL1, content::Referrer(),
327 content::PAGE_TRANSITION_TYPED, std::string());
328 test_rvh()->SendNavigate(0, kExistingURL1);
329 EXPECT_TRUE(notifications.Check1AndReset(
330 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
331
332 const GURL kExistingURL2("http://foo/bee");
333 controller.LoadURL(kExistingURL2, content::Referrer(),
334 content::PAGE_TRANSITION_TYPED, std::string());
335 test_rvh()->SendNavigate(1, kExistingURL2);
336 EXPECT_TRUE(notifications.Check1AndReset(
337 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
338
339 // Now make a pending back/forward navigation. The zeroth entry should be
340 // pending.
341 controller.GoBack();
342 EXPECT_EQ(0U, notifications.size());
343 EXPECT_EQ(0, controller.GetPendingEntryIndex());
344 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
345
346 // Before that commits, do a new navigation.
347 const GURL kNewURL("http://foo/see");
348 content::LoadCommittedDetails details;
349 test_rvh()->SendNavigate(3, kNewURL);
350
351 // There should no longer be any pending entry, and the third navigation we
352 // just made should be committed.
353 EXPECT_TRUE(notifications.Check1AndReset(
354 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
355 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
356 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
357 EXPECT_EQ(kNewURL, controller.GetActiveEntry()->GetURL());
358 }
359
360 // Tests navigating to an existing URL when there is a pending new navigation.
361 // This will happen if the user enters a URL, but before that commits, the
362 // current page fires history.back().
363 TEST_F(NavigationControllerTest, LoadURL_BackPreemptsPending) {
364 NavigationControllerImpl& controller = controller_impl();
365 TestNotificationTracker notifications;
366 RegisterForAllNavNotifications(&notifications, &controller);
367
368 // First make some history.
369 const GURL kExistingURL1("http://foo/eh");
370 controller.LoadURL(kExistingURL1, content::Referrer(),
371 content::PAGE_TRANSITION_TYPED, std::string());
372 test_rvh()->SendNavigate(0, kExistingURL1);
373 EXPECT_TRUE(notifications.Check1AndReset(
374 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
375
376 const GURL kExistingURL2("http://foo/bee");
377 controller.LoadURL(kExistingURL2, content::Referrer(),
378 content::PAGE_TRANSITION_TYPED, std::string());
379 test_rvh()->SendNavigate(1, kExistingURL2);
380 EXPECT_TRUE(notifications.Check1AndReset(
381 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
382
383 // Now make a pending new navigation.
384 const GURL kNewURL("http://foo/see");
385 controller.LoadURL(
386 kNewURL, content::Referrer(), content::PAGE_TRANSITION_TYPED,
387 std::string());
388 EXPECT_EQ(0U, notifications.size());
389 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
390 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
391
392 // Before that commits, a back navigation from the renderer commits.
393 test_rvh()->SendNavigate(0, kExistingURL1);
394
395 // There should no longer be any pending entry, and the back navigation we
396 // just made should be committed.
397 EXPECT_TRUE(notifications.Check1AndReset(
398 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
399 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
400 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
401 EXPECT_EQ(kExistingURL1, controller.GetActiveEntry()->GetURL());
402 }
403
404 // Tests an ignored navigation when there is a pending new navigation.
405 // This will happen if the user enters a URL, but before that commits, the
406 // current blank page reloads. See http://crbug.com/77507.
407 TEST_F(NavigationControllerTest, LoadURL_IgnorePreemptsPending) {
408 NavigationControllerImpl& controller = controller_impl();
409 TestNotificationTracker notifications;
410 RegisterForAllNavNotifications(&notifications, &controller);
411
412 // Set a WebContentsDelegate to listen for state changes.
413 scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
414 EXPECT_FALSE(contents()->GetDelegate());
415 contents()->SetDelegate(delegate.get());
416
417 // Without any navigations, the renderer starts at about:blank.
418 const GURL kExistingURL("about:blank");
419
420 // Now make a pending new navigation.
421 const GURL kNewURL("http://eh");
422 controller.LoadURL(
423 kNewURL, content::Referrer(), content::PAGE_TRANSITION_TYPED,
424 std::string());
425 EXPECT_EQ(0U, notifications.size());
426 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
427 EXPECT_TRUE(controller.GetPendingEntry());
428 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
429 EXPECT_EQ(1, delegate->navigation_state_change_count());
430
431 // Before that commits, a document.write and location.reload can cause the
432 // renderer to send a FrameNavigate with page_id -1.
433 test_rvh()->SendNavigate(-1, kExistingURL);
434
435 // This should clear the pending entry and notify of a navigation state
436 // change, so that we do not keep displaying kNewURL.
437 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
438 EXPECT_FALSE(controller.GetPendingEntry());
439 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
440 EXPECT_EQ(2, delegate->navigation_state_change_count());
441
442 contents()->SetDelegate(NULL);
443 }
444
445 // Tests that the pending entry state is correct after an abort.
446 TEST_F(NavigationControllerTest, LoadURL_AbortCancelsPending) {
447 NavigationControllerImpl& controller = controller_impl();
448 TestNotificationTracker notifications;
449 RegisterForAllNavNotifications(&notifications, &controller);
450
451 // Set a WebContentsDelegate to listen for state changes.
452 scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
453 EXPECT_FALSE(contents()->GetDelegate());
454 contents()->SetDelegate(delegate.get());
455
456 // Without any navigations, the renderer starts at about:blank.
457 const GURL kExistingURL("about:blank");
458
459 // Now make a pending new navigation.
460 const GURL kNewURL("http://eh");
461 controller.LoadURL(
462 kNewURL, content::Referrer(), content::PAGE_TRANSITION_TYPED,
463 std::string());
464 EXPECT_EQ(0U, notifications.size());
465 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
466 EXPECT_TRUE(controller.GetPendingEntry());
467 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
468 EXPECT_EQ(1, delegate->navigation_state_change_count());
469
470 // It may abort before committing, if it's a download or due to a stop or
471 // a new navigation from the user.
472 ViewHostMsg_DidFailProvisionalLoadWithError_Params params;
473 params.frame_id = 1;
474 params.is_main_frame = true;
475 params.error_code = net::ERR_ABORTED;
476 params.error_description = string16();
477 params.url = kNewURL;
478 params.showing_repost_interstitial = false;
479 test_rvh()->OnMessageReceived(
480 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
481 params));
482
483 // This should clear the pending entry and notify of a navigation state
484 // change, so that we do not keep displaying kNewURL.
485 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
486 EXPECT_FALSE(controller.GetPendingEntry());
487 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
488 EXPECT_EQ(2, delegate->navigation_state_change_count());
489
490 contents()->SetDelegate(NULL);
491 }
492
493 // Tests that the pending entry state is correct after a redirect and abort.
494 // http://crbug.com/83031.
495 TEST_F(NavigationControllerTest, LoadURL_RedirectAbortCancelsPending) {
496 NavigationControllerImpl& controller = controller_impl();
497 TestNotificationTracker notifications;
498 RegisterForAllNavNotifications(&notifications, &controller);
499
500 // Set a WebContentsDelegate to listen for state changes.
501 scoped_ptr<TestWebContentsDelegate> delegate(new TestWebContentsDelegate());
502 EXPECT_FALSE(contents()->GetDelegate());
503 contents()->SetDelegate(delegate.get());
504
505 // Without any navigations, the renderer starts at about:blank.
506 const GURL kExistingURL("about:blank");
507
508 // Now make a pending new navigation.
509 const GURL kNewURL("http://eh");
510 controller.LoadURL(
511 kNewURL, content::Referrer(), content::PAGE_TRANSITION_TYPED,
512 std::string());
513 EXPECT_EQ(0U, notifications.size());
514 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
515 EXPECT_TRUE(controller.GetPendingEntry());
516 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
517 EXPECT_EQ(1, delegate->navigation_state_change_count());
518
519 // Now the navigation redirects.
520 const GURL kRedirectURL("http://bee");
521 test_rvh()->OnMessageReceived(
522 ViewHostMsg_DidRedirectProvisionalLoad(0, // routing_id
523 -1, // pending page_id
524 GURL(), // opener
525 kNewURL, // old url
526 kRedirectURL)); // new url
527
528 // We don't want to change the NavigationEntry's url, in case it cancels.
529 // Prevents regression of http://crbug.com/77786.
530 EXPECT_EQ(kNewURL, controller.GetPendingEntry()->GetURL());
531
532 // It may abort before committing, if it's a download or due to a stop or
533 // a new navigation from the user.
534 ViewHostMsg_DidFailProvisionalLoadWithError_Params params;
535 params.frame_id = 1;
536 params.is_main_frame = true;
537 params.error_code = net::ERR_ABORTED;
538 params.error_description = string16();
539 params.url = kRedirectURL;
540 params.showing_repost_interstitial = false;
541 test_rvh()->OnMessageReceived(
542 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
543 params));
544
545 // This should clear the pending entry and notify of a navigation state
546 // change, so that we do not keep displaying kNewURL.
547 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
548 EXPECT_FALSE(controller.GetPendingEntry());
549 EXPECT_EQ(-1, controller.GetLastCommittedEntryIndex());
550 EXPECT_EQ(2, delegate->navigation_state_change_count());
551
552 contents()->SetDelegate(NULL);
553 }
554
555 TEST_F(NavigationControllerTest, Reload) {
556 NavigationControllerImpl& controller = controller_impl();
557 TestNotificationTracker notifications;
558 RegisterForAllNavNotifications(&notifications, &controller);
559
560 const GURL url1("http://foo1");
561
562 controller.LoadURL(
563 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
564 EXPECT_EQ(0U, notifications.size());
565 test_rvh()->SendNavigate(0, url1);
566 EXPECT_TRUE(notifications.Check1AndReset(
567 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
568 controller.GetActiveEntry()->SetTitle(ASCIIToUTF16("Title"));
569 controller.Reload(true);
570 EXPECT_EQ(0U, notifications.size());
571
572 // The reload is pending.
573 EXPECT_EQ(controller.GetEntryCount(), 1);
574 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
575 EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
576 EXPECT_TRUE(controller.GetLastCommittedEntry());
577 EXPECT_TRUE(controller.GetPendingEntry());
578 EXPECT_FALSE(controller.CanGoBack());
579 EXPECT_FALSE(controller.CanGoForward());
580 // Make sure the title has been cleared (will be redrawn just after reload).
581 // Avoids a stale cached title when the new page being reloaded has no title.
582 // See http://crbug.com/96041.
583 EXPECT_TRUE(controller.GetActiveEntry()->GetTitle().empty());
584
585 test_rvh()->SendNavigate(0, url1);
586 EXPECT_TRUE(notifications.Check1AndReset(
587 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
588
589 // Now the reload is committed.
590 EXPECT_EQ(controller.GetEntryCount(), 1);
591 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
592 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
593 EXPECT_TRUE(controller.GetLastCommittedEntry());
594 EXPECT_FALSE(controller.GetPendingEntry());
595 EXPECT_FALSE(controller.CanGoBack());
596 EXPECT_FALSE(controller.CanGoForward());
597 }
598
599 // Tests what happens when a reload navigation produces a new page.
600 TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) {
601 NavigationControllerImpl& controller = controller_impl();
602 TestNotificationTracker notifications;
603 RegisterForAllNavNotifications(&notifications, &controller);
604
605 const GURL url1("http://foo1");
606 const GURL url2("http://foo2");
607
608 controller.LoadURL(
609 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
610 test_rvh()->SendNavigate(0, url1);
611 EXPECT_TRUE(notifications.Check1AndReset(
612 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
613
614 controller.Reload(true);
615 EXPECT_EQ(0U, notifications.size());
616
617 test_rvh()->SendNavigate(1, url2);
618 EXPECT_TRUE(notifications.Check1AndReset(
619 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
620
621 // Now the reload is committed.
622 EXPECT_EQ(controller.GetEntryCount(), 2);
623 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
624 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
625 EXPECT_TRUE(controller.GetLastCommittedEntry());
626 EXPECT_FALSE(controller.GetPendingEntry());
627 EXPECT_TRUE(controller.CanGoBack());
628 EXPECT_FALSE(controller.CanGoForward());
629 }
630
631 // Tests what happens when we navigate back successfully
632 TEST_F(NavigationControllerTest, Back) {
633 NavigationControllerImpl& controller = controller_impl();
634 TestNotificationTracker notifications;
635 RegisterForAllNavNotifications(&notifications, &controller);
636
637 const GURL url1("http://foo1");
638 test_rvh()->SendNavigate(0, url1);
639 EXPECT_TRUE(notifications.Check1AndReset(
640 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
641
642 const GURL url2("http://foo2");
643 test_rvh()->SendNavigate(1, url2);
644 EXPECT_TRUE(notifications.Check1AndReset(
645 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
646
647 controller.GoBack();
648 EXPECT_EQ(0U, notifications.size());
649
650 // We should now have a pending navigation to go back.
651 EXPECT_EQ(controller.GetEntryCount(), 2);
652 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
653 EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
654 EXPECT_TRUE(controller.GetLastCommittedEntry());
655 EXPECT_TRUE(controller.GetPendingEntry());
656 EXPECT_FALSE(controller.CanGoBack());
657 EXPECT_TRUE(controller.CanGoForward());
658
659 test_rvh()->SendNavigate(0, url2);
660 EXPECT_TRUE(notifications.Check1AndReset(
661 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
662
663 // The back navigation completed successfully.
664 EXPECT_EQ(controller.GetEntryCount(), 2);
665 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
666 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
667 EXPECT_TRUE(controller.GetLastCommittedEntry());
668 EXPECT_FALSE(controller.GetPendingEntry());
669 EXPECT_FALSE(controller.CanGoBack());
670 EXPECT_TRUE(controller.CanGoForward());
671 }
672
673 // Tests what happens when a back navigation produces a new page.
674 TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
675 NavigationControllerImpl& controller = controller_impl();
676 TestNotificationTracker notifications;
677 RegisterForAllNavNotifications(&notifications, &controller);
678
679 const GURL url1("http://foo/1");
680 const GURL url2("http://foo/2");
681 const GURL url3("http://foo/3");
682
683 controller.LoadURL(
684 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
685 test_rvh()->SendNavigate(0, url1);
686 EXPECT_TRUE(notifications.Check1AndReset(
687 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
688
689 controller.LoadURL(
690 url2, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
691 test_rvh()->SendNavigate(1, url2);
692 EXPECT_TRUE(notifications.Check1AndReset(
693 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
694
695 controller.GoBack();
696 EXPECT_EQ(0U, notifications.size());
697
698 // We should now have a pending navigation to go back.
699 EXPECT_EQ(controller.GetEntryCount(), 2);
700 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
701 EXPECT_EQ(controller.GetPendingEntryIndex(), 0);
702 EXPECT_TRUE(controller.GetLastCommittedEntry());
703 EXPECT_TRUE(controller.GetPendingEntry());
704 EXPECT_FALSE(controller.CanGoBack());
705 EXPECT_TRUE(controller.CanGoForward());
706
707 test_rvh()->SendNavigate(2, url3);
708 EXPECT_TRUE(notifications.Check1AndReset(
709 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
710
711 // The back navigation resulted in a completely new navigation.
712 // TODO(darin): perhaps this behavior will be confusing to users?
713 EXPECT_EQ(controller.GetEntryCount(), 3);
714 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
715 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
716 EXPECT_TRUE(controller.GetLastCommittedEntry());
717 EXPECT_FALSE(controller.GetPendingEntry());
718 EXPECT_TRUE(controller.CanGoBack());
719 EXPECT_FALSE(controller.CanGoForward());
720 }
721
722 // Receives a back message when there is a new pending navigation entry.
723 TEST_F(NavigationControllerTest, Back_NewPending) {
724 NavigationControllerImpl& controller = controller_impl();
725 TestNotificationTracker notifications;
726 RegisterForAllNavNotifications(&notifications, &controller);
727
728 const GURL kUrl1("http://foo1");
729 const GURL kUrl2("http://foo2");
730 const GURL kUrl3("http://foo3");
731
732 // First navigate two places so we have some back history.
733 test_rvh()->SendNavigate(0, kUrl1);
734 EXPECT_TRUE(notifications.Check1AndReset(
735 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
736
737 // controller.LoadURL(kUrl2, content::PAGE_TRANSITION_TYPED);
738 test_rvh()->SendNavigate(1, kUrl2);
739 EXPECT_TRUE(notifications.Check1AndReset(
740 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
741
742 // Now start a new pending navigation and go back before it commits.
743 controller.LoadURL(
744 kUrl3, content::Referrer(), content::PAGE_TRANSITION_TYPED,
745 std::string());
746 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
747 EXPECT_EQ(kUrl3, controller.GetPendingEntry()->GetURL());
748 controller.GoBack();
749
750 // The pending navigation should now be the "back" item and the new one
751 // should be gone.
752 EXPECT_EQ(0, controller.GetPendingEntryIndex());
753 EXPECT_EQ(kUrl1, controller.GetPendingEntry()->GetURL());
754 }
755
756 // Receives a back message when there is a different renavigation already
757 // pending.
758 TEST_F(NavigationControllerTest, Back_OtherBackPending) {
759 NavigationControllerImpl& controller = controller_impl();
760 const GURL kUrl1("http://foo/1");
761 const GURL kUrl2("http://foo/2");
762 const GURL kUrl3("http://foo/3");
763
764 // First navigate three places so we have some back history.
765 test_rvh()->SendNavigate(0, kUrl1);
766 test_rvh()->SendNavigate(1, kUrl2);
767 test_rvh()->SendNavigate(2, kUrl3);
768
769 // With nothing pending, say we get a navigation to the second entry.
770 test_rvh()->SendNavigate(1, kUrl2);
771
772 // We know all the entries have the same site instance, so we can just grab
773 // a random one for looking up other entries.
774 SiteInstance* site_instance =
775 NavigationEntryImpl::FromNavigationEntry(
776 controller.GetLastCommittedEntry())->site_instance();
777
778 // That second URL should be the last committed and it should have gotten the
779 // new title.
780 EXPECT_EQ(kUrl2, controller.GetEntryWithPageID(site_instance, 1)->GetURL());
781 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
782 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
783
784 // Now go forward to the last item again and say it was committed.
785 controller.GoForward();
786 test_rvh()->SendNavigate(2, kUrl3);
787
788 // Now start going back one to the second page. It will be pending.
789 controller.GoBack();
790 EXPECT_EQ(1, controller.GetPendingEntryIndex());
791 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
792
793 // Not synthesize a totally new back event to the first page. This will not
794 // match the pending one.
795 test_rvh()->SendNavigate(0, kUrl1);
796
797 // The committed navigation should clear the pending entry.
798 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
799
800 // But the navigated entry should be the last committed.
801 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
802 EXPECT_EQ(kUrl1, controller.GetLastCommittedEntry()->GetURL());
803 }
804
805 // Tests what happens when we navigate forward successfully.
806 TEST_F(NavigationControllerTest, Forward) {
807 NavigationControllerImpl& controller = controller_impl();
808 TestNotificationTracker notifications;
809 RegisterForAllNavNotifications(&notifications, &controller);
810
811 const GURL url1("http://foo1");
812 const GURL url2("http://foo2");
813
814 test_rvh()->SendNavigate(0, url1);
815 EXPECT_TRUE(notifications.Check1AndReset(
816 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
817
818 test_rvh()->SendNavigate(1, url2);
819 EXPECT_TRUE(notifications.Check1AndReset(
820 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
821
822 controller.GoBack();
823 test_rvh()->SendNavigate(0, url1);
824 EXPECT_TRUE(notifications.Check1AndReset(
825 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
826
827 controller.GoForward();
828
829 // We should now have a pending navigation to go forward.
830 EXPECT_EQ(controller.GetEntryCount(), 2);
831 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
832 EXPECT_EQ(controller.GetPendingEntryIndex(), 1);
833 EXPECT_TRUE(controller.GetLastCommittedEntry());
834 EXPECT_TRUE(controller.GetPendingEntry());
835 EXPECT_TRUE(controller.CanGoBack());
836 EXPECT_FALSE(controller.CanGoForward());
837
838 test_rvh()->SendNavigate(1, url2);
839 EXPECT_TRUE(notifications.Check1AndReset(
840 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
841
842 // The forward navigation completed successfully.
843 EXPECT_EQ(controller.GetEntryCount(), 2);
844 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
845 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
846 EXPECT_TRUE(controller.GetLastCommittedEntry());
847 EXPECT_FALSE(controller.GetPendingEntry());
848 EXPECT_TRUE(controller.CanGoBack());
849 EXPECT_FALSE(controller.CanGoForward());
850 }
851
852 // Tests what happens when a forward navigation produces a new page.
853 TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
854 NavigationControllerImpl& controller = controller_impl();
855 TestNotificationTracker notifications;
856 RegisterForAllNavNotifications(&notifications, &controller);
857
858 const GURL url1("http://foo1");
859 const GURL url2("http://foo2");
860 const GURL url3("http://foo3");
861
862 test_rvh()->SendNavigate(0, url1);
863 EXPECT_TRUE(notifications.Check1AndReset(
864 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
865 test_rvh()->SendNavigate(1, url2);
866 EXPECT_TRUE(notifications.Check1AndReset(
867 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
868
869 controller.GoBack();
870 test_rvh()->SendNavigate(0, url1);
871 EXPECT_TRUE(notifications.Check1AndReset(
872 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
873
874 controller.GoForward();
875 EXPECT_EQ(0U, notifications.size());
876
877 // Should now have a pending navigation to go forward.
878 EXPECT_EQ(controller.GetEntryCount(), 2);
879 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
880 EXPECT_EQ(controller.GetPendingEntryIndex(), 1);
881 EXPECT_TRUE(controller.GetLastCommittedEntry());
882 EXPECT_TRUE(controller.GetPendingEntry());
883 EXPECT_TRUE(controller.CanGoBack());
884 EXPECT_FALSE(controller.CanGoForward());
885
886 test_rvh()->SendNavigate(2, url3);
887 EXPECT_TRUE(notifications.Check2AndReset(
888 content::NOTIFICATION_NAV_LIST_PRUNED,
889 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
890
891 EXPECT_EQ(controller.GetEntryCount(), 2);
892 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
893 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
894 EXPECT_TRUE(controller.GetLastCommittedEntry());
895 EXPECT_FALSE(controller.GetPendingEntry());
896 EXPECT_TRUE(controller.CanGoBack());
897 EXPECT_FALSE(controller.CanGoForward());
898 }
899
900 // Two consequent navigation for the same URL entered in should be considered
901 // as SAME_PAGE navigation even when we are redirected to some other page.
902 TEST_F(NavigationControllerTest, Redirect) {
903 NavigationControllerImpl& controller = controller_impl();
904 TestNotificationTracker notifications;
905 RegisterForAllNavNotifications(&notifications, &controller);
906
907 const GURL url1("http://foo1");
908 const GURL url2("http://foo2"); // Redirection target
909
910 // First request
911 controller.LoadURL(
912 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
913
914 EXPECT_EQ(0U, notifications.size());
915 test_rvh()->SendNavigate(0, url2);
916 EXPECT_TRUE(notifications.Check1AndReset(
917 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
918
919 // Second request
920 controller.LoadURL(
921 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
922
923 EXPECT_TRUE(controller.GetPendingEntry());
924 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
925 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
926
927 ViewHostMsg_FrameNavigate_Params params;
928 params.page_id = 0;
929 params.url = url2;
930 params.transition = content::PAGE_TRANSITION_SERVER_REDIRECT;
931 params.redirects.push_back(GURL("http://foo1"));
932 params.redirects.push_back(GURL("http://foo2"));
933 params.should_update_history = false;
934 params.gesture = NavigationGestureAuto;
935 params.is_post = false;
936 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url2));
937
938 content::LoadCommittedDetails details;
939
940 EXPECT_EQ(0U, notifications.size());
941 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
942 EXPECT_TRUE(notifications.Check1AndReset(
943 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
944
945 EXPECT_TRUE(details.type == content::NAVIGATION_TYPE_SAME_PAGE);
946 EXPECT_EQ(controller.GetEntryCount(), 1);
947 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
948 EXPECT_TRUE(controller.GetLastCommittedEntry());
949 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
950 EXPECT_FALSE(controller.GetPendingEntry());
951 EXPECT_EQ(url2, controller.GetActiveEntry()->GetURL());
952
953 EXPECT_FALSE(controller.CanGoBack());
954 EXPECT_FALSE(controller.CanGoForward());
955 }
956
957 // Similar to Redirect above, but the first URL is requested by POST,
958 // the second URL is requested by GET. NavigationEntry::has_post_data_
959 // must be cleared. http://crbug.com/21245
960 TEST_F(NavigationControllerTest, PostThenRedirect) {
961 NavigationControllerImpl& controller = controller_impl();
962 TestNotificationTracker notifications;
963 RegisterForAllNavNotifications(&notifications, &controller);
964
965 const GURL url1("http://foo1");
966 const GURL url2("http://foo2"); // Redirection target
967
968 // First request as POST
969 controller.LoadURL(
970 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
971 controller.GetActiveEntry()->SetHasPostData(true);
972
973 EXPECT_EQ(0U, notifications.size());
974 test_rvh()->SendNavigate(0, url2);
975 EXPECT_TRUE(notifications.Check1AndReset(
976 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
977
978 // Second request
979 controller.LoadURL(
980 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
981
982 EXPECT_TRUE(controller.GetPendingEntry());
983 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
984 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
985
986 ViewHostMsg_FrameNavigate_Params params;
987 params.page_id = 0;
988 params.url = url2;
989 params.transition = content::PAGE_TRANSITION_SERVER_REDIRECT;
990 params.redirects.push_back(GURL("http://foo1"));
991 params.redirects.push_back(GURL("http://foo2"));
992 params.should_update_history = false;
993 params.gesture = NavigationGestureAuto;
994 params.is_post = false;
995 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url2));
996
997 content::LoadCommittedDetails details;
998
999 EXPECT_EQ(0U, notifications.size());
1000 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
1001 EXPECT_TRUE(notifications.Check1AndReset(
1002 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1003
1004 EXPECT_TRUE(details.type == content::NAVIGATION_TYPE_SAME_PAGE);
1005 EXPECT_EQ(controller.GetEntryCount(), 1);
1006 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1007 EXPECT_TRUE(controller.GetLastCommittedEntry());
1008 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1009 EXPECT_FALSE(controller.GetPendingEntry());
1010 EXPECT_EQ(url2, controller.GetActiveEntry()->GetURL());
1011 EXPECT_FALSE(controller.GetActiveEntry()->GetHasPostData());
1012
1013 EXPECT_FALSE(controller.CanGoBack());
1014 EXPECT_FALSE(controller.CanGoForward());
1015 }
1016
1017 // A redirect right off the bat should be a NEW_PAGE.
1018 TEST_F(NavigationControllerTest, ImmediateRedirect) {
1019 NavigationControllerImpl& controller = controller_impl();
1020 TestNotificationTracker notifications;
1021 RegisterForAllNavNotifications(&notifications, &controller);
1022
1023 const GURL url1("http://foo1");
1024 const GURL url2("http://foo2"); // Redirection target
1025
1026 // First request
1027 controller.LoadURL(
1028 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1029
1030 EXPECT_TRUE(controller.GetPendingEntry());
1031 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1032 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
1033
1034 ViewHostMsg_FrameNavigate_Params params;
1035 params.page_id = 0;
1036 params.url = url2;
1037 params.transition = content::PAGE_TRANSITION_SERVER_REDIRECT;
1038 params.redirects.push_back(GURL("http://foo1"));
1039 params.redirects.push_back(GURL("http://foo2"));
1040 params.should_update_history = false;
1041 params.gesture = NavigationGestureAuto;
1042 params.is_post = false;
1043 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url2));
1044
1045 content::LoadCommittedDetails details;
1046
1047 EXPECT_EQ(0U, notifications.size());
1048 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
1049 EXPECT_TRUE(notifications.Check1AndReset(
1050 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1051
1052 EXPECT_TRUE(details.type == content::NAVIGATION_TYPE_NEW_PAGE);
1053 EXPECT_EQ(controller.GetEntryCount(), 1);
1054 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1055 EXPECT_TRUE(controller.GetLastCommittedEntry());
1056 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1057 EXPECT_FALSE(controller.GetPendingEntry());
1058 EXPECT_EQ(url2, controller.GetActiveEntry()->GetURL());
1059
1060 EXPECT_FALSE(controller.CanGoBack());
1061 EXPECT_FALSE(controller.CanGoForward());
1062 }
1063
1064 // Tests navigation via link click within a subframe. A new navigation entry
1065 // should be created.
1066 TEST_F(NavigationControllerTest, NewSubframe) {
1067 NavigationControllerImpl& controller = controller_impl();
1068 TestNotificationTracker notifications;
1069 RegisterForAllNavNotifications(&notifications, &controller);
1070
1071 const GURL url1("http://foo1");
1072 test_rvh()->SendNavigate(0, url1);
1073 EXPECT_TRUE(notifications.Check1AndReset(
1074 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1075
1076 const GURL url2("http://foo2");
1077 ViewHostMsg_FrameNavigate_Params params;
1078 params.page_id = 1;
1079 params.url = url2;
1080 params.transition = content::PAGE_TRANSITION_MANUAL_SUBFRAME;
1081 params.should_update_history = false;
1082 params.gesture = NavigationGestureUser;
1083 params.is_post = false;
1084 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url2));
1085
1086 content::LoadCommittedDetails details;
1087 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
1088 EXPECT_TRUE(notifications.Check1AndReset(
1089 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1090 EXPECT_EQ(url1, details.previous_url);
1091 EXPECT_FALSE(details.is_in_page);
1092 EXPECT_FALSE(details.is_main_frame);
1093
1094 // The new entry should be appended.
1095 EXPECT_EQ(2, controller.GetEntryCount());
1096
1097 // New entry should refer to the new page, but the old URL (entries only
1098 // reflect the toplevel URL).
1099 EXPECT_EQ(url1, details.entry->GetURL());
1100 EXPECT_EQ(params.page_id, details.entry->GetPageID());
1101 }
1102
1103 // Some pages create a popup, then write an iframe into it. This causes a
1104 // subframe navigation without having any committed entry. Such navigations
1105 // just get thrown on the ground, but we shouldn't crash.
1106 TEST_F(NavigationControllerTest, SubframeOnEmptyPage) {
1107 NavigationControllerImpl& controller = controller_impl();
1108 TestNotificationTracker notifications;
1109 RegisterForAllNavNotifications(&notifications, &controller);
1110
1111 // Navigation controller currently has no entries.
1112 const GURL url("http://foo2");
1113 ViewHostMsg_FrameNavigate_Params params;
1114 params.page_id = 1;
1115 params.url = url;
1116 params.transition = content::PAGE_TRANSITION_AUTO_SUBFRAME;
1117 params.should_update_history = false;
1118 params.gesture = NavigationGestureAuto;
1119 params.is_post = false;
1120 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url));
1121
1122 content::LoadCommittedDetails details;
1123 EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
1124 EXPECT_EQ(0U, notifications.size());
1125 }
1126
1127 // Auto subframes are ones the page loads automatically like ads. They should
1128 // not create new navigation entries.
1129 TEST_F(NavigationControllerTest, AutoSubframe) {
1130 NavigationControllerImpl& controller = controller_impl();
1131 TestNotificationTracker notifications;
1132 RegisterForAllNavNotifications(&notifications, &controller);
1133
1134 const GURL url1("http://foo1");
1135 test_rvh()->SendNavigate(0, url1);
1136 EXPECT_TRUE(notifications.Check1AndReset(
1137 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1138
1139 const GURL url2("http://foo2");
1140 ViewHostMsg_FrameNavigate_Params params;
1141 params.page_id = 0;
1142 params.url = url2;
1143 params.transition = content::PAGE_TRANSITION_AUTO_SUBFRAME;
1144 params.should_update_history = false;
1145 params.gesture = NavigationGestureUser;
1146 params.is_post = false;
1147 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url2));
1148
1149 // Navigating should do nothing.
1150 content::LoadCommittedDetails details;
1151 EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
1152 EXPECT_EQ(0U, notifications.size());
1153
1154 // There should still be only one entry.
1155 EXPECT_EQ(1, controller.GetEntryCount());
1156 }
1157
1158 // Tests navigation and then going back to a subframe navigation.
1159 TEST_F(NavigationControllerTest, BackSubframe) {
1160 NavigationControllerImpl& controller = controller_impl();
1161 TestNotificationTracker notifications;
1162 RegisterForAllNavNotifications(&notifications, &controller);
1163
1164 // Main page.
1165 const GURL url1("http://foo1");
1166 test_rvh()->SendNavigate(0, url1);
1167 EXPECT_TRUE(notifications.Check1AndReset(
1168 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1169
1170 // First manual subframe navigation.
1171 const GURL url2("http://foo2");
1172 ViewHostMsg_FrameNavigate_Params params;
1173 params.page_id = 1;
1174 params.url = url2;
1175 params.transition = content::PAGE_TRANSITION_MANUAL_SUBFRAME;
1176 params.should_update_history = false;
1177 params.gesture = NavigationGestureUser;
1178 params.is_post = false;
1179 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url2));
1180
1181 // This should generate a new entry.
1182 content::LoadCommittedDetails details;
1183 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
1184 EXPECT_TRUE(notifications.Check1AndReset(
1185 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1186 EXPECT_EQ(2, controller.GetEntryCount());
1187
1188 // Second manual subframe navigation should also make a new entry.
1189 const GURL url3("http://foo3");
1190 params.page_id = 2;
1191 params.url = url3;
1192 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
1193 EXPECT_TRUE(notifications.Check1AndReset(
1194 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1195 EXPECT_EQ(3, controller.GetEntryCount());
1196 EXPECT_EQ(2, controller.GetCurrentEntryIndex());
1197
1198 // Go back one.
1199 controller.GoBack();
1200 params.url = url2;
1201 params.page_id = 1;
1202 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
1203 EXPECT_TRUE(notifications.Check1AndReset(
1204 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1205 EXPECT_EQ(3, controller.GetEntryCount());
1206 EXPECT_EQ(1, controller.GetCurrentEntryIndex());
1207
1208 // Go back one more.
1209 controller.GoBack();
1210 params.url = url1;
1211 params.page_id = 0;
1212 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
1213 EXPECT_TRUE(notifications.Check1AndReset(
1214 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1215 EXPECT_EQ(3, controller.GetEntryCount());
1216 EXPECT_EQ(0, controller.GetCurrentEntryIndex());
1217 }
1218
1219 TEST_F(NavigationControllerTest, LinkClick) {
1220 NavigationControllerImpl& controller = controller_impl();
1221 TestNotificationTracker notifications;
1222 RegisterForAllNavNotifications(&notifications, &controller);
1223
1224 const GURL url1("http://foo1");
1225 const GURL url2("http://foo2");
1226
1227 test_rvh()->SendNavigate(0, url1);
1228 EXPECT_TRUE(notifications.Check1AndReset(
1229 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1230
1231 test_rvh()->SendNavigate(1, url2);
1232 EXPECT_TRUE(notifications.Check1AndReset(
1233 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1234
1235 // Should not have produced a new session history entry.
1236 EXPECT_EQ(controller.GetEntryCount(), 2);
1237 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1238 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1239 EXPECT_TRUE(controller.GetLastCommittedEntry());
1240 EXPECT_FALSE(controller.GetPendingEntry());
1241 EXPECT_TRUE(controller.CanGoBack());
1242 EXPECT_FALSE(controller.CanGoForward());
1243 }
1244
1245 TEST_F(NavigationControllerTest, InPage) {
1246 NavigationControllerImpl& controller = controller_impl();
1247 TestNotificationTracker notifications;
1248 RegisterForAllNavNotifications(&notifications, &controller);
1249
1250 // Main page.
1251 const GURL url1("http://foo");
1252 test_rvh()->SendNavigate(0, url1);
1253 EXPECT_TRUE(notifications.Check1AndReset(
1254 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1255
1256 // First navigation.
1257 const GURL url2("http://foo#a");
1258 ViewHostMsg_FrameNavigate_Params params;
1259 params.page_id = 1;
1260 params.url = url2;
1261 params.transition = content::PAGE_TRANSITION_LINK;
1262 params.should_update_history = false;
1263 params.gesture = NavigationGestureUser;
1264 params.is_post = false;
1265 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url2));
1266
1267 // This should generate a new entry.
1268 content::LoadCommittedDetails details;
1269 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
1270 EXPECT_TRUE(notifications.Check1AndReset(
1271 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1272 EXPECT_TRUE(details.is_in_page);
1273 EXPECT_FALSE(details.did_replace_entry);
1274 EXPECT_EQ(2, controller.GetEntryCount());
1275
1276 // Go back one.
1277 ViewHostMsg_FrameNavigate_Params back_params(params);
1278 controller.GoBack();
1279 back_params.url = url1;
1280 back_params.page_id = 0;
1281 EXPECT_TRUE(controller.RendererDidNavigate(back_params, &details));
1282 EXPECT_TRUE(notifications.Check1AndReset(
1283 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1284 // is_in_page is false in that case but should be true.
1285 // See comment in AreURLsInPageNavigation() in navigation_controller.cc
1286 // EXPECT_TRUE(details.is_in_page);
1287 EXPECT_EQ(2, controller.GetEntryCount());
1288 EXPECT_EQ(0, controller.GetCurrentEntryIndex());
1289 EXPECT_EQ(back_params.url, controller.GetActiveEntry()->GetURL());
1290
1291 // Go forward
1292 ViewHostMsg_FrameNavigate_Params forward_params(params);
1293 controller.GoForward();
1294 forward_params.url = url2;
1295 forward_params.page_id = 1;
1296 EXPECT_TRUE(controller.RendererDidNavigate(forward_params, &details));
1297 EXPECT_TRUE(notifications.Check1AndReset(
1298 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1299 EXPECT_TRUE(details.is_in_page);
1300 EXPECT_EQ(2, controller.GetEntryCount());
1301 EXPECT_EQ(1, controller.GetCurrentEntryIndex());
1302 EXPECT_EQ(forward_params.url,
1303 controller.GetActiveEntry()->GetURL());
1304
1305 // Now go back and forward again. This is to work around a bug where we would
1306 // compare the incoming URL with the last committed entry rather than the
1307 // one identified by an existing page ID. This would result in the second URL
1308 // losing the reference fragment when you navigate away from it and then back.
1309 controller.GoBack();
1310 EXPECT_TRUE(controller.RendererDidNavigate(back_params, &details));
1311 controller.GoForward();
1312 EXPECT_TRUE(controller.RendererDidNavigate(forward_params, &details));
1313 EXPECT_EQ(forward_params.url,
1314 controller.GetActiveEntry()->GetURL());
1315
1316 // Finally, navigate to an unrelated URL to make sure in_page is not sticky.
1317 const GURL url3("http://bar");
1318 params.page_id = 2;
1319 params.url = url3;
1320 notifications.Reset();
1321 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
1322 EXPECT_TRUE(notifications.Check1AndReset(
1323 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1324 EXPECT_FALSE(details.is_in_page);
1325 }
1326
1327 TEST_F(NavigationControllerTest, InPage_Replace) {
1328 NavigationControllerImpl& controller = controller_impl();
1329 TestNotificationTracker notifications;
1330 RegisterForAllNavNotifications(&notifications, &controller);
1331
1332 // Main page.
1333 const GURL url1("http://foo");
1334 test_rvh()->SendNavigate(0, url1);
1335 EXPECT_TRUE(notifications.Check1AndReset(
1336 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1337
1338 // First navigation.
1339 const GURL url2("http://foo#a");
1340 ViewHostMsg_FrameNavigate_Params params;
1341 params.page_id = 0; // Same page_id
1342 params.url = url2;
1343 params.transition = content::PAGE_TRANSITION_LINK;
1344 params.should_update_history = false;
1345 params.gesture = NavigationGestureUser;
1346 params.is_post = false;
1347 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url2));
1348
1349 // This should NOT generate a new entry, nor prune the list.
1350 content::LoadCommittedDetails details;
1351 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
1352 EXPECT_TRUE(notifications.Check1AndReset(
1353 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1354 EXPECT_TRUE(details.is_in_page);
1355 EXPECT_TRUE(details.did_replace_entry);
1356 EXPECT_EQ(1, controller.GetEntryCount());
1357 }
1358
1359 // Tests for http://crbug.com/40395
1360 // Simulates this:
1361 // <script>
1362 // window.location.replace("#a");
1363 // window.location='http://foo3/';
1364 // </script>
1365 TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
1366 NavigationControllerImpl& controller = controller_impl();
1367 TestNotificationTracker notifications;
1368 RegisterForAllNavNotifications(&notifications, &controller);
1369
1370 // Load an initial page.
1371 {
1372 const GURL url("http://foo/");
1373 test_rvh()->SendNavigate(0, url);
1374 EXPECT_TRUE(notifications.Check1AndReset(
1375 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1376 }
1377
1378 // Navigate to a new page.
1379 {
1380 const GURL url("http://foo2/");
1381 test_rvh()->SendNavigate(1, url);
1382 controller.DocumentLoadedInFrame();
1383 EXPECT_TRUE(notifications.Check1AndReset(
1384 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1385 }
1386
1387 // Navigate within the page.
1388 {
1389 const GURL url("http://foo2/#a");
1390 ViewHostMsg_FrameNavigate_Params params;
1391 params.page_id = 1; // Same page_id
1392 params.url = url;
1393 params.transition = content::PAGE_TRANSITION_LINK;
1394 params.redirects.push_back(url);
1395 params.should_update_history = true;
1396 params.gesture = NavigationGestureUnknown;
1397 params.is_post = false;
1398 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url));
1399
1400 // This should NOT generate a new entry, nor prune the list.
1401 content::LoadCommittedDetails details;
1402 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
1403 EXPECT_TRUE(notifications.Check1AndReset(
1404 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1405 EXPECT_TRUE(details.is_in_page);
1406 EXPECT_TRUE(details.did_replace_entry);
1407 EXPECT_EQ(2, controller.GetEntryCount());
1408 }
1409
1410 // Perform a client redirect to a new page.
1411 {
1412 const GURL url("http://foo3/");
1413 ViewHostMsg_FrameNavigate_Params params;
1414 params.page_id = 2; // New page_id
1415 params.url = url;
1416 params.transition = content::PAGE_TRANSITION_CLIENT_REDIRECT;
1417 params.redirects.push_back(GURL("http://foo2/#a"));
1418 params.redirects.push_back(url);
1419 params.should_update_history = true;
1420 params.gesture = NavigationGestureUnknown;
1421 params.is_post = false;
1422 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url));
1423
1424 // This SHOULD generate a new entry.
1425 content::LoadCommittedDetails details;
1426 EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
1427 EXPECT_TRUE(notifications.Check1AndReset(
1428 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1429 EXPECT_FALSE(details.is_in_page);
1430 EXPECT_EQ(3, controller.GetEntryCount());
1431 }
1432
1433 // Verify that BACK brings us back to http://foo2/.
1434 {
1435 const GURL url("http://foo2/");
1436 controller.GoBack();
1437 test_rvh()->SendNavigate(1, url);
1438 EXPECT_TRUE(notifications.Check1AndReset(
1439 content::NOTIFICATION_NAV_ENTRY_COMMITTED));
1440 EXPECT_EQ(url, controller.GetActiveEntry()->GetURL());
1441 }
1442 }
1443
1444 // NotificationObserver implementation used in verifying we've received the
1445 // content::NOTIFICATION_NAV_LIST_PRUNED method.
1446 class PrunedListener : public content::NotificationObserver {
1447 public:
1448 explicit PrunedListener(NavigationControllerImpl* controller)
1449 : notification_count_(0) {
1450 registrar_.Add(this, content::NOTIFICATION_NAV_LIST_PRUNED,
1451 content::Source<NavigationController>(controller));
1452 }
1453
1454 virtual void Observe(int type,
1455 const content::NotificationSource& source,
1456 const content::NotificationDetails& details) {
1457 if (type == content::NOTIFICATION_NAV_LIST_PRUNED) {
1458 notification_count_++;
1459 details_ = *(content::Details<content::PrunedDetails>(details).ptr());
1460 }
1461 }
1462
1463 // Number of times NAV_LIST_PRUNED has been observed.
1464 int notification_count_;
1465
1466 // Details from the last NAV_LIST_PRUNED.
1467 content::PrunedDetails details_;
1468
1469 private:
1470 content::NotificationRegistrar registrar_;
1471
1472 DISALLOW_COPY_AND_ASSIGN(PrunedListener);
1473 };
1474
1475 // Tests that we limit the number of navigation entries created correctly.
1476 TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
1477 NavigationControllerImpl& controller = controller_impl();
1478 size_t original_count = NavigationControllerImpl::max_entry_count();
1479 const int kMaxEntryCount = 5;
1480
1481 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
1482
1483 int url_index;
1484 // Load up to the max count, all entries should be there.
1485 for (url_index = 0; url_index < kMaxEntryCount; url_index++) {
1486 GURL url(StringPrintf("http://www.a.com/%d", url_index));
1487 controller.LoadURL(
1488 url, content::Referrer(), content::PAGE_TRANSITION_TYPED,
1489 std::string());
1490 test_rvh()->SendNavigate(url_index, url);
1491 }
1492
1493 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
1494
1495 // Created a PrunedListener to observe prune notifications.
1496 PrunedListener listener(&controller);
1497
1498 // Navigate some more.
1499 GURL url(StringPrintf("http://www.a.com/%d", url_index));
1500 controller.LoadURL(
1501 url, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1502 test_rvh()->SendNavigate(url_index, url);
1503 url_index++;
1504
1505 // We should have got a pruned navigation.
1506 EXPECT_EQ(1, listener.notification_count_);
1507 EXPECT_TRUE(listener.details_.from_front);
1508 EXPECT_EQ(1, listener.details_.count);
1509
1510 // We expect http://www.a.com/0 to be gone.
1511 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
1512 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
1513 GURL("http:////www.a.com/1"));
1514
1515 // More navigations.
1516 for (int i = 0; i < 3; i++) {
1517 url = GURL(StringPrintf("http:////www.a.com/%d", url_index));
1518 controller.LoadURL(
1519 url, content::Referrer(), content::PAGE_TRANSITION_TYPED,
1520 std::string());
1521 test_rvh()->SendNavigate(url_index, url);
1522 url_index++;
1523 }
1524 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
1525 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(),
1526 GURL("http:////www.a.com/4"));
1527
1528 NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
1529 }
1530
1531 // Tests that we can do a restore and navigate to the restored entries and
1532 // everything is updated properly. This can be tricky since there is no
1533 // SiteInstance for the entries created initially.
1534 TEST_F(NavigationControllerTest, RestoreNavigate) {
1535 // Create a NavigationController with a restored set of tabs.
1536 GURL url("http://foo");
1537 std::vector<NavigationEntry*> entries;
1538 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
1539 url, content::Referrer(), content::PAGE_TRANSITION_RELOAD, false,
1540 std::string(), browser_context());
1541 entry->SetPageID(0);
1542 entry->SetTitle(ASCIIToUTF16("Title"));
1543 entry->SetContentState("state");
1544 entries.push_back(entry);
1545 TabContents our_contents(
1546 browser_context(), NULL, MSG_ROUTING_NONE, NULL, NULL);
1547 NavigationControllerImpl& our_controller = our_contents.GetControllerImpl();
1548 our_controller.Restore(0, true, &entries);
1549 ASSERT_EQ(0u, entries.size());
1550
1551 // Before navigating to the restored entry, it should have a restore_type
1552 // and no SiteInstance.
1553 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION,
1554 NavigationEntryImpl::FromNavigationEntry(
1555 our_controller.GetEntryAtIndex(0))->restore_type());
1556 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
1557 our_controller.GetEntryAtIndex(0))->site_instance());
1558
1559 // After navigating, we should have one entry, and it should be "pending".
1560 // It should now have a SiteInstance and no restore_type.
1561 our_controller.GoToIndex(0);
1562 EXPECT_EQ(1, our_controller.GetEntryCount());
1563 EXPECT_EQ(our_controller.GetEntryAtIndex(0),
1564 our_controller.GetPendingEntry());
1565 EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
1566 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
1567 NavigationEntryImpl::FromNavigationEntry
1568 (our_controller.GetEntryAtIndex(0))->restore_type());
1569 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
1570 our_controller.GetEntryAtIndex(0))->site_instance());
1571
1572 // Say we navigated to that entry.
1573 ViewHostMsg_FrameNavigate_Params params;
1574 params.page_id = 0;
1575 params.url = url;
1576 params.transition = content::PAGE_TRANSITION_LINK;
1577 params.should_update_history = false;
1578 params.gesture = NavigationGestureUser;
1579 params.is_post = false;
1580 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url));
1581 content::LoadCommittedDetails details;
1582 our_controller.RendererDidNavigate(params, &details);
1583
1584 // There should be no longer any pending entry and one committed one. This
1585 // means that we were able to locate the entry, assign its site instance, and
1586 // commit it properly.
1587 EXPECT_EQ(1, our_controller.GetEntryCount());
1588 EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
1589 EXPECT_FALSE(our_controller.GetPendingEntry());
1590 EXPECT_EQ(url,
1591 NavigationEntryImpl::FromNavigationEntry(
1592 our_controller.GetLastCommittedEntry())->site_instance()->
1593 GetSite());
1594 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
1595 NavigationEntryImpl::FromNavigationEntry(
1596 our_controller.GetEntryAtIndex(0))->restore_type());
1597 }
1598
1599 // Tests that we can still navigate to a restored entry after a different
1600 // navigation fails and clears the pending entry. http://crbug.com/90085
1601 TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
1602 // Create a NavigationController with a restored set of tabs.
1603 GURL url("http://foo");
1604 std::vector<NavigationEntry*> entries;
1605 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
1606 url, content::Referrer(), content::PAGE_TRANSITION_RELOAD, false,
1607 std::string(), browser_context());
1608 entry->SetPageID(0);
1609 entry->SetTitle(ASCIIToUTF16("Title"));
1610 entry->SetContentState("state");
1611 entries.push_back(entry);
1612 TabContents our_contents(
1613 browser_context(), NULL, MSG_ROUTING_NONE, NULL, NULL);
1614 NavigationControllerImpl& our_controller = our_contents.GetControllerImpl();
1615 our_controller.Restore(0, true, &entries);
1616 ASSERT_EQ(0u, entries.size());
1617
1618 // Before navigating to the restored entry, it should have a restore_type
1619 // and no SiteInstance.
1620 EXPECT_EQ(NavigationEntryImpl::RESTORE_LAST_SESSION,
1621 NavigationEntryImpl::FromNavigationEntry(
1622 our_controller.GetEntryAtIndex(0))->restore_type());
1623 EXPECT_FALSE(NavigationEntryImpl::FromNavigationEntry(
1624 our_controller.GetEntryAtIndex(0))->site_instance());
1625
1626 // After navigating, we should have one entry, and it should be "pending".
1627 // It should now have a SiteInstance and no restore_type.
1628 our_controller.GoToIndex(0);
1629 EXPECT_EQ(1, our_controller.GetEntryCount());
1630 EXPECT_EQ(our_controller.GetEntryAtIndex(0),
1631 our_controller.GetPendingEntry());
1632 EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->GetPageID());
1633 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
1634 NavigationEntryImpl::FromNavigationEntry(
1635 our_controller.GetEntryAtIndex(0))->restore_type());
1636 EXPECT_TRUE(NavigationEntryImpl::FromNavigationEntry(
1637 our_controller.GetEntryAtIndex(0))->site_instance());
1638
1639 // This pending navigation may have caused a different navigation to fail,
1640 // which causes the pending entry to be cleared.
1641 TestRenderViewHost* rvh =
1642 static_cast<TestRenderViewHost*>(our_contents.GetRenderViewHost());
1643 ViewHostMsg_DidFailProvisionalLoadWithError_Params fail_load_params;
1644 fail_load_params.frame_id = 1;
1645 fail_load_params.is_main_frame = true;
1646 fail_load_params.error_code = net::ERR_ABORTED;
1647 fail_load_params.error_description = string16();
1648 fail_load_params.url = url;
1649 fail_load_params.showing_repost_interstitial = false;
1650 rvh->OnMessageReceived(
1651 ViewHostMsg_DidFailProvisionalLoadWithError(0, // routing_id
1652 fail_load_params));
1653
1654 // Now the pending restored entry commits.
1655 ViewHostMsg_FrameNavigate_Params params;
1656 params.page_id = 0;
1657 params.url = url;
1658 params.transition = content::PAGE_TRANSITION_LINK;
1659 params.should_update_history = false;
1660 params.gesture = NavigationGestureUser;
1661 params.is_post = false;
1662 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url));
1663 content::LoadCommittedDetails details;
1664 our_controller.RendererDidNavigate(params, &details);
1665
1666 // There should be no pending entry and one committed one.
1667 EXPECT_EQ(1, our_controller.GetEntryCount());
1668 EXPECT_EQ(0, our_controller.GetLastCommittedEntryIndex());
1669 EXPECT_FALSE(our_controller.GetPendingEntry());
1670 EXPECT_EQ(url,
1671 NavigationEntryImpl::FromNavigationEntry(
1672 our_controller.GetLastCommittedEntry())->site_instance()->
1673 GetSite());
1674 EXPECT_EQ(NavigationEntryImpl::RESTORE_NONE,
1675 NavigationEntryImpl::FromNavigationEntry(
1676 our_controller.GetEntryAtIndex(0))->restore_type());
1677 }
1678
1679 // Make sure that the page type and stuff is correct after an interstitial.
1680 TEST_F(NavigationControllerTest, Interstitial) {
1681 NavigationControllerImpl& controller = controller_impl();
1682 // First navigate somewhere normal.
1683 const GURL url1("http://foo");
1684 controller.LoadURL(
1685 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1686 test_rvh()->SendNavigate(0, url1);
1687
1688 // Now navigate somewhere with an interstitial.
1689 const GURL url2("http://bar");
1690 controller.LoadURL(
1691 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1692 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
1693 set_page_type(content::PAGE_TYPE_INTERSTITIAL);
1694
1695 // At this point the interstitial will be displayed and the load will still
1696 // be pending. If the user continues, the load will commit.
1697 test_rvh()->SendNavigate(1, url2);
1698
1699 // The page should be a normal page again.
1700 EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
1701 EXPECT_EQ(content::PAGE_TYPE_NORMAL,
1702 controller.GetLastCommittedEntry()->GetPageType());
1703 }
1704
1705 TEST_F(NavigationControllerTest, RemoveEntry) {
1706 NavigationControllerImpl& controller = controller_impl();
1707 const GURL url1("http://foo/1");
1708 const GURL url2("http://foo/2");
1709 const GURL url3("http://foo/3");
1710 const GURL url4("http://foo/4");
1711 const GURL url5("http://foo/5");
1712 const GURL pending_url("http://foo/pending");
1713 const GURL default_url("http://foo/default");
1714
1715 controller.LoadURL(
1716 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1717 test_rvh()->SendNavigate(0, url1);
1718 controller.LoadURL(
1719 url2, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1720 test_rvh()->SendNavigate(1, url2);
1721 controller.LoadURL(
1722 url3, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1723 test_rvh()->SendNavigate(2, url3);
1724 controller.LoadURL(
1725 url4, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1726 test_rvh()->SendNavigate(3, url4);
1727 controller.LoadURL(
1728 url5, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1729 test_rvh()->SendNavigate(4, url5);
1730
1731 // Try to remove the last entry. Will fail because it is the current entry.
1732 controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1);
1733 EXPECT_EQ(5, controller.GetEntryCount());
1734 EXPECT_EQ(4, controller.GetLastCommittedEntryIndex());
1735
1736 // Go back and remove the last entry.
1737 controller.GoBack();
1738 test_rvh()->SendNavigate(3, url4);
1739 controller.RemoveEntryAtIndex(controller.GetEntryCount() - 1);
1740 EXPECT_EQ(4, controller.GetEntryCount());
1741 EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
1742 EXPECT_FALSE(controller.GetPendingEntry());
1743
1744 // Remove an entry which is not the last committed one.
1745 controller.RemoveEntryAtIndex(0);
1746 EXPECT_EQ(3, controller.GetEntryCount());
1747 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
1748 EXPECT_FALSE(controller.GetPendingEntry());
1749
1750 // Remove the 2 remaining entries.
1751 controller.RemoveEntryAtIndex(1);
1752 controller.RemoveEntryAtIndex(0);
1753
1754 // This should leave us with only the last committed entry.
1755 EXPECT_EQ(1, controller.GetEntryCount());
1756 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
1757 }
1758
1759 // Tests the transient entry, making sure it goes away with all navigations.
1760 TEST_F(NavigationControllerTest, TransientEntry) {
1761 NavigationControllerImpl& controller = controller_impl();
1762 TestNotificationTracker notifications;
1763 RegisterForAllNavNotifications(&notifications, &controller);
1764
1765 const GURL url0("http://foo/0");
1766 const GURL url1("http://foo/1");
1767 const GURL url2("http://foo/2");
1768 const GURL url3("http://foo/3");
1769 const GURL url4("http://foo/4");
1770 const GURL transient_url("http://foo/transient");
1771
1772 controller.LoadURL(
1773 url0, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1774 test_rvh()->SendNavigate(0, url0);
1775 controller.LoadURL(
1776 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1777 test_rvh()->SendNavigate(1, url1);
1778
1779 notifications.Reset();
1780
1781 // Adding a transient with no pending entry.
1782 NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
1783 transient_entry->SetURL(transient_url);
1784 controller.AddTransientEntry(transient_entry);
1785
1786 // We should not have received any notifications.
1787 EXPECT_EQ(0U, notifications.size());
1788
1789 // Check our state.
1790 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
1791 EXPECT_EQ(controller.GetEntryCount(), 3);
1792 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
1793 EXPECT_EQ(controller.GetPendingEntryIndex(), -1);
1794 EXPECT_TRUE(controller.GetLastCommittedEntry());
1795 EXPECT_FALSE(controller.GetPendingEntry());
1796 EXPECT_TRUE(controller.CanGoBack());
1797 EXPECT_FALSE(controller.CanGoForward());
1798 EXPECT_EQ(contents()->GetMaxPageID(), 1);
1799
1800 // Navigate.
1801 controller.LoadURL(
1802 url2, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1803 test_rvh()->SendNavigate(2, url2);
1804
1805 // We should have navigated, transient entry should be gone.
1806 EXPECT_EQ(url2, controller.GetActiveEntry()->GetURL());
1807 EXPECT_EQ(controller.GetEntryCount(), 3);
1808
1809 // Add a transient again, then navigate with no pending entry this time.
1810 transient_entry = new NavigationEntryImpl;
1811 transient_entry->SetURL(transient_url);
1812 controller.AddTransientEntry(transient_entry);
1813 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
1814 test_rvh()->SendNavigate(3, url3);
1815 // Transient entry should be gone.
1816 EXPECT_EQ(url3, controller.GetActiveEntry()->GetURL());
1817 EXPECT_EQ(controller.GetEntryCount(), 4);
1818
1819 // Initiate a navigation, add a transient then commit navigation.
1820 controller.LoadURL(
1821 url4, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
1822 transient_entry = new NavigationEntryImpl;
1823 transient_entry->SetURL(transient_url);
1824 controller.AddTransientEntry(transient_entry);
1825 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
1826 test_rvh()->SendNavigate(4, url4);
1827 EXPECT_EQ(url4, controller.GetActiveEntry()->GetURL());
1828 EXPECT_EQ(controller.GetEntryCount(), 5);
1829
1830 // Add a transient and go back. This should simply remove the transient.
1831 transient_entry = new NavigationEntryImpl;
1832 transient_entry->SetURL(transient_url);
1833 controller.AddTransientEntry(transient_entry);
1834 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
1835 EXPECT_TRUE(controller.CanGoBack());
1836 EXPECT_FALSE(controller.CanGoForward());
1837 controller.GoBack();
1838 // Transient entry should be gone.
1839 EXPECT_EQ(url4, controller.GetActiveEntry()->GetURL());
1840 EXPECT_EQ(controller.GetEntryCount(), 5);
1841 test_rvh()->SendNavigate(3, url3);
1842
1843 // Add a transient and go to an entry before the current one.
1844 transient_entry = new NavigationEntryImpl;
1845 transient_entry->SetURL(transient_url);
1846 controller.AddTransientEntry(transient_entry);
1847 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
1848 controller.GoToIndex(1);
1849 // The navigation should have been initiated, transient entry should be gone.
1850 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
1851 // Visible entry does not update for history navigations until commit.
1852 EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
1853 test_rvh()->SendNavigate(1, url1);
1854 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
1855
1856 // Add a transient and go to an entry after the current one.
1857 transient_entry = new NavigationEntryImpl;
1858 transient_entry->SetURL(transient_url);
1859 controller.AddTransientEntry(transient_entry);
1860 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
1861 controller.GoToIndex(3);
1862 // The navigation should have been initiated, transient entry should be gone.
1863 // Because of the transient entry that is removed, going to index 3 makes us
1864 // land on url2 (which is visible after the commit).
1865 EXPECT_EQ(url2, controller.GetActiveEntry()->GetURL());
1866 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
1867 test_rvh()->SendNavigate(2, url2);
1868 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
1869
1870 // Add a transient and go forward.
1871 transient_entry = new NavigationEntryImpl;
1872 transient_entry->SetURL(transient_url);
1873 controller.AddTransientEntry(transient_entry);
1874 EXPECT_EQ(transient_url, controller.GetActiveEntry()->GetURL());
1875 EXPECT_TRUE(controller.CanGoForward());
1876 controller.GoForward();
1877 // We should have navigated, transient entry should be gone.
1878 EXPECT_EQ(url3, controller.GetActiveEntry()->GetURL());
1879 EXPECT_EQ(url2, controller.GetVisibleEntry()->GetURL());
1880 test_rvh()->SendNavigate(3, url3);
1881 EXPECT_EQ(url3, controller.GetVisibleEntry()->GetURL());
1882
1883 // Ensure the URLS are correct.
1884 EXPECT_EQ(controller.GetEntryCount(), 5);
1885 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url0);
1886 EXPECT_EQ(controller.GetEntryAtIndex(1)->GetURL(), url1);
1887 EXPECT_EQ(controller.GetEntryAtIndex(2)->GetURL(), url2);
1888 EXPECT_EQ(controller.GetEntryAtIndex(3)->GetURL(), url3);
1889 EXPECT_EQ(controller.GetEntryAtIndex(4)->GetURL(), url4);
1890 }
1891
1892 // Tests that the URLs for renderer-initiated navigations are not displayed to
1893 // the user until the navigation commits, to prevent URL spoof attacks.
1894 // See http://crbug.com/99016.
1895 TEST_F(NavigationControllerTest, DontShowRendererURLUntilCommit) {
1896 NavigationControllerImpl& controller = controller_impl();
1897 TestNotificationTracker notifications;
1898 RegisterForAllNavNotifications(&notifications, &controller);
1899
1900 const GURL url0("http://foo/0");
1901 const GURL url1("http://foo/1");
1902
1903 // For typed navigations (browser-initiated), both active and visible entries
1904 // should update before commit.
1905 controller.LoadURL(url0, content::Referrer(),
1906 content::PAGE_TRANSITION_TYPED, std::string());
1907 EXPECT_EQ(url0, controller.GetActiveEntry()->GetURL());
1908 EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
1909 test_rvh()->SendNavigate(0, url0);
1910
1911 // For link clicks (renderer-initiated navigations), the active entry should
1912 // update before commit but the visible should not.
1913 controller.LoadURLFromRenderer(url1, content::Referrer(),
1914 content::PAGE_TRANSITION_LINK,
1915 std::string());
1916 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
1917 EXPECT_EQ(url0, controller.GetVisibleEntry()->GetURL());
1918 EXPECT_TRUE(
1919 NavigationEntryImpl::FromNavigationEntry(controller.GetPendingEntry())->
1920 is_renderer_initiated());
1921
1922 // After commit, both should be updated, and we should no longer treat the
1923 // entry as renderer-initiated.
1924 test_rvh()->SendNavigate(1, url1);
1925 EXPECT_EQ(url1, controller.GetActiveEntry()->GetURL());
1926 EXPECT_EQ(url1, controller.GetVisibleEntry()->GetURL());
1927 EXPECT_FALSE(
1928 NavigationEntryImpl::FromNavigationEntry(
1929 controller.GetLastCommittedEntry())->is_renderer_initiated());
1930
1931 notifications.Reset();
1932 }
1933
1934 // Tests that IsInPageNavigation returns appropriate results. Prevents
1935 // regression for bug 1126349.
1936 TEST_F(NavigationControllerTest, IsInPageNavigation) {
1937 NavigationControllerImpl& controller = controller_impl();
1938 // Navigate to URL with no refs.
1939 const GURL url("http://www.google.com/home.html");
1940 test_rvh()->SendNavigate(0, url);
1941
1942 // Reloading the page is not an in-page navigation.
1943 EXPECT_FALSE(controller.IsURLInPageNavigation(url));
1944 const GURL other_url("http://www.google.com/add.html");
1945 EXPECT_FALSE(controller.IsURLInPageNavigation(other_url));
1946 const GURL url_with_ref("http://www.google.com/home.html#my_ref");
1947 EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref));
1948
1949 // Navigate to URL with refs.
1950 test_rvh()->SendNavigate(1, url_with_ref);
1951
1952 // Reloading the page is not an in-page navigation.
1953 EXPECT_FALSE(controller.IsURLInPageNavigation(url_with_ref));
1954 EXPECT_FALSE(controller.IsURLInPageNavigation(url));
1955 EXPECT_FALSE(controller.IsURLInPageNavigation(other_url));
1956 const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref");
1957 EXPECT_TRUE(controller.IsURLInPageNavigation(
1958 other_url_with_ref));
1959 }
1960
1961 // Some pages can have subframes with the same base URL (minus the reference) as
1962 // the main page. Even though this is hard, it can happen, and we don't want
1963 // these subframe navigations to affect the toplevel document. They should
1964 // instead be ignored. http://crbug.com/5585
1965 TEST_F(NavigationControllerTest, SameSubframe) {
1966 NavigationControllerImpl& controller = controller_impl();
1967 // Navigate the main frame.
1968 const GURL url("http://www.google.com/");
1969 test_rvh()->SendNavigate(0, url);
1970
1971 // We should be at the first navigation entry.
1972 EXPECT_EQ(controller.GetEntryCount(), 1);
1973 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1974
1975 // Navigate a subframe that would normally count as in-page.
1976 const GURL subframe("http://www.google.com/#");
1977 ViewHostMsg_FrameNavigate_Params params;
1978 params.page_id = 0;
1979 params.url = subframe;
1980 params.transition = content::PAGE_TRANSITION_AUTO_SUBFRAME;
1981 params.should_update_history = false;
1982 params.gesture = NavigationGestureAuto;
1983 params.is_post = false;
1984 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(subframe));
1985 content::LoadCommittedDetails details;
1986 EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
1987
1988 // Nothing should have changed.
1989 EXPECT_EQ(controller.GetEntryCount(), 1);
1990 EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 0);
1991 }
1992
1993 // Make sure that on cloning a tabcontents and going back needs_reload is false.
1994 TEST_F(NavigationControllerTest, CloneAndGoBack) {
1995 NavigationControllerImpl& controller = controller_impl();
1996 const GURL url1("http://foo1");
1997 const GURL url2("http://foo2");
1998
1999 NavigateAndCommit(url1);
2000 NavigateAndCommit(url2);
2001
2002 scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
2003
2004 ASSERT_EQ(2, clone->GetController().GetEntryCount());
2005 EXPECT_TRUE(clone->GetController().NeedsReload());
2006 clone->GetController().GoBack();
2007 // Navigating back should have triggered needs_reload_ to go false.
2008 EXPECT_FALSE(clone->GetController().NeedsReload());
2009 }
2010
2011 // Make sure that cloning a tabcontents doesn't copy interstitials.
2012 TEST_F(NavigationControllerTest, CloneOmitsInterstitials) {
2013 NavigationControllerImpl& controller = controller_impl();
2014 const GURL url1("http://foo1");
2015 const GURL url2("http://foo2");
2016
2017 NavigateAndCommit(url1);
2018 NavigateAndCommit(url2);
2019
2020 // Add an interstitial entry. Should be deleted with controller.
2021 NavigationEntryImpl* interstitial_entry = new NavigationEntryImpl();
2022 interstitial_entry->set_page_type(content::PAGE_TYPE_INTERSTITIAL);
2023 controller.AddTransientEntry(interstitial_entry);
2024
2025 scoped_ptr<WebContents> clone(controller.GetWebContents()->Clone());
2026
2027 ASSERT_EQ(2, clone->GetController().GetEntryCount());
2028 }
2029
2030 // Tests a subframe navigation while a toplevel navigation is pending.
2031 // http://crbug.com/43967
2032 TEST_F(NavigationControllerTest, SubframeWhilePending) {
2033 NavigationControllerImpl& controller = controller_impl();
2034 // Load the first page.
2035 const GURL url1("http://foo/");
2036 NavigateAndCommit(url1);
2037
2038 // Now start a pending load to a totally different page, but don't commit it.
2039 const GURL url2("http://bar/");
2040 controller.LoadURL(
2041 url2, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
2042
2043 // Send a subframe update from the first page, as if one had just
2044 // automatically loaded. Auto subframes don't increment the page ID.
2045 const GURL url1_sub("http://foo/subframe");
2046 ViewHostMsg_FrameNavigate_Params params;
2047 params.page_id = controller.GetLastCommittedEntry()->GetPageID();
2048 params.url = url1_sub;
2049 params.transition = content::PAGE_TRANSITION_AUTO_SUBFRAME;
2050 params.should_update_history = false;
2051 params.gesture = NavigationGestureAuto;
2052 params.is_post = false;
2053 params.content_state = webkit_glue::CreateHistoryStateForURL(GURL(url1_sub));
2054 content::LoadCommittedDetails details;
2055
2056 // This should return false meaning that nothing was actually updated.
2057 EXPECT_FALSE(controller.RendererDidNavigate(params, &details));
2058
2059 // The notification should have updated the last committed one, and not
2060 // the pending load.
2061 EXPECT_EQ(url1, controller.GetLastCommittedEntry()->GetURL());
2062
2063 // The active entry should be unchanged by the subframe load.
2064 EXPECT_EQ(url2, controller.GetActiveEntry()->GetURL());
2065 }
2066
2067 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
2068 TEST_F(NavigationControllerTest, CopyStateFromAndPrune) {
2069 NavigationControllerImpl& controller = controller_impl();
2070 const GURL url1("http://foo/1");
2071 const GURL url2("http://foo/2");
2072 const GURL url3("http://foo/3");
2073
2074 NavigateAndCommit(url1);
2075 NavigateAndCommit(url2);
2076
2077 // First two entries should have the same SiteInstance.
2078 SiteInstance* instance1 =
2079 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(0));
2080 SiteInstance* instance2 =
2081 GetSiteInstanceFromEntry(controller.GetEntryAtIndex(1));
2082 EXPECT_EQ(instance1, instance2);
2083 EXPECT_EQ(0, controller.GetEntryAtIndex(0)->GetPageID());
2084 EXPECT_EQ(1, controller.GetEntryAtIndex(1)->GetPageID());
2085 EXPECT_EQ(1, contents()->GetMaxPageIDForSiteInstance(instance1));
2086
2087 scoped_ptr<TestWebContents> other_contents(
2088 static_cast<TestWebContents*>(CreateTestWebContents()));
2089 NavigationControllerImpl& other_controller =
2090 other_contents->GetControllerImpl();
2091 other_contents->NavigateAndCommit(url3);
2092 other_contents->ExpectSetHistoryLengthAndPrune(
2093 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
2094 other_controller.GetEntryAtIndex(0)->GetPageID());
2095 other_controller.CopyStateFromAndPrune(&controller);
2096
2097 // other_controller should now contain the 3 urls: url1, url2 and url3.
2098
2099 ASSERT_EQ(3, other_controller.GetEntryCount());
2100
2101 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
2102
2103 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2104 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->GetURL());
2105 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->GetURL());
2106 EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
2107 EXPECT_EQ(1, other_controller.GetEntryAtIndex(1)->GetPageID());
2108 EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
2109
2110 // A new SiteInstance should be used for the new tab.
2111 SiteInstance* instance3 =
2112 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(2));
2113 EXPECT_NE(instance3, instance1);
2114
2115 // The max page ID map should be copied over and updated with the max page ID
2116 // from the current tab.
2117 EXPECT_EQ(1, other_contents->GetMaxPageIDForSiteInstance(instance1));
2118 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance3));
2119 }
2120
2121 // Test CopyStateFromAndPrune with 2 urls, the first selected and nothing in
2122 // the target.
2123 TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) {
2124 NavigationControllerImpl& controller = controller_impl();
2125 const GURL url1("http://foo1");
2126 const GURL url2("http://foo2");
2127 const GURL url3("http://foo3");
2128
2129 NavigateAndCommit(url1);
2130 NavigateAndCommit(url2);
2131 controller.GoBack();
2132
2133 scoped_ptr<TestWebContents> other_contents(
2134 static_cast<TestWebContents*>(CreateTestWebContents()));
2135 NavigationControllerImpl& other_controller =
2136 other_contents->GetControllerImpl();
2137 other_contents->ExpectSetHistoryLengthAndPrune(NULL, 1, -1);
2138 other_controller.CopyStateFromAndPrune(&controller);
2139
2140 // other_controller should now contain the 1 url: url1.
2141
2142 ASSERT_EQ(1, other_controller.GetEntryCount());
2143
2144 ASSERT_EQ(0, other_controller.GetCurrentEntryIndex());
2145
2146 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2147 EXPECT_EQ(0, other_controller.GetEntryAtIndex(0)->GetPageID());
2148
2149 // The max page ID map should be copied over and updated with the max page ID
2150 // from the current tab.
2151 SiteInstance* instance1 =
2152 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
2153 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
2154 }
2155
2156 // Test CopyStateFromAndPrune with 2 urls, the first selected and nothing in
2157 // the target.
2158 TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) {
2159 NavigationControllerImpl& controller = controller_impl();
2160 const GURL url1("http://foo1");
2161 const GURL url2("http://foo2");
2162 const GURL url3("http://foo3");
2163
2164 NavigateAndCommit(url1);
2165 NavigateAndCommit(url2);
2166 controller.GoBack();
2167
2168 scoped_ptr<TestWebContents> other_contents(
2169 static_cast<TestWebContents*>(CreateTestWebContents()));
2170 NavigationControllerImpl& other_controller =
2171 other_contents->GetControllerImpl();
2172 other_controller.LoadURL(
2173 url3, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
2174 other_contents->ExpectSetHistoryLengthAndPrune(NULL, 1, -1);
2175 other_controller.CopyStateFromAndPrune(&controller);
2176
2177 // other_controller should now contain 1 entry for url1, and a pending entry
2178 // for url3.
2179
2180 ASSERT_EQ(1, other_controller.GetEntryCount());
2181
2182 EXPECT_EQ(0, other_controller.GetCurrentEntryIndex());
2183
2184 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2185
2186 // And there should be a pending entry for url3.
2187 ASSERT_TRUE(other_controller.GetPendingEntry());
2188
2189 EXPECT_EQ(url3, other_controller.GetPendingEntry()->GetURL());
2190
2191 // The max page ID map should be copied over and updated with the max page ID
2192 // from the current tab.
2193 SiteInstance* instance1 =
2194 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0));
2195 EXPECT_EQ(0, other_contents->GetMaxPageIDForSiteInstance(instance1));
2196 }
2197
2198 // Tests CopyStateFromAndPrune with 3 urls in source, 1 in dest,
2199 // when the max entry count is 3. We should prune one entry.
2200 TEST_F(NavigationControllerTest, CopyStateFromAndPruneMaxEntries) {
2201 NavigationControllerImpl& controller = controller_impl();
2202 size_t original_count = NavigationControllerImpl::max_entry_count();
2203 const int kMaxEntryCount = 3;
2204
2205 NavigationControllerImpl::set_max_entry_count_for_testing(kMaxEntryCount);
2206
2207 const GURL url1("http://foo/1");
2208 const GURL url2("http://foo/2");
2209 const GURL url3("http://foo/3");
2210 const GURL url4("http://foo/4");
2211
2212 // Create a PrunedListener to observe prune notifications.
2213 PrunedListener listener(&controller);
2214
2215 NavigateAndCommit(url1);
2216 NavigateAndCommit(url2);
2217 NavigateAndCommit(url3);
2218
2219 scoped_ptr<TestWebContents> other_contents(
2220 static_cast<TestWebContents*>(CreateTestWebContents()));
2221 NavigationControllerImpl& other_controller =
2222 other_contents->GetControllerImpl();
2223 other_contents->NavigateAndCommit(url4);
2224 other_contents->ExpectSetHistoryLengthAndPrune(
2225 GetSiteInstanceFromEntry(other_controller.GetEntryAtIndex(0)), 2,
2226 other_controller.GetEntryAtIndex(0)->GetPageID());
2227 other_controller.CopyStateFromAndPrune(&controller);
2228
2229 // We should have received a pruned notification.
2230 EXPECT_EQ(1, listener.notification_count_);
2231 EXPECT_TRUE(listener.details_.from_front);
2232 EXPECT_EQ(1, listener.details_.count);
2233
2234 // other_controller should now contain only 3 urls: url2, url3 and url4.
2235
2236 ASSERT_EQ(3, other_controller.GetEntryCount());
2237
2238 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
2239
2240 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(0)->GetURL());
2241 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2242 EXPECT_EQ(url4, other_controller.GetEntryAtIndex(2)->GetURL());
2243 EXPECT_EQ(1, other_controller.GetEntryAtIndex(0)->GetPageID());
2244 EXPECT_EQ(2, other_controller.GetEntryAtIndex(1)->GetPageID());
2245 EXPECT_EQ(0, other_controller.GetEntryAtIndex(2)->GetPageID());
2246
2247 NavigationControllerImpl::set_max_entry_count_for_testing(original_count);
2248 }
2249
2250 // Tests that navigations initiated from the page (with the history object)
2251 // work as expected without navigation entries.
2252 TEST_F(NavigationControllerTest, HistoryNavigate) {
2253 NavigationControllerImpl& controller = controller_impl();
2254 const GURL url1("http://foo/1");
2255 const GURL url2("http://foo/2");
2256 const GURL url3("http://foo/3");
2257
2258 NavigateAndCommit(url1);
2259 NavigateAndCommit(url2);
2260 NavigateAndCommit(url3);
2261 controller.GoBack();
2262 contents()->CommitPendingNavigation();
2263
2264 // Simulate the page calling history.back(), it should not create a pending
2265 // entry.
2266 contents()->OnGoToEntryAtOffset(-1);
2267 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
2268 // The actual cross-navigation is suspended until the current RVH tells us
2269 // it unloaded, simulate that.
2270 contents()->ProceedWithCrossSiteNavigation();
2271 // Also make sure we told the page to navigate.
2272 const IPC::Message* message =
2273 process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
2274 ASSERT_TRUE(message != NULL);
2275 Tuple1<ViewMsg_Navigate_Params> nav_params;
2276 ViewMsg_Navigate::Read(message, &nav_params);
2277 EXPECT_EQ(url1, nav_params.a.url);
2278 process()->sink().ClearMessages();
2279
2280 // Now test history.forward()
2281 contents()->OnGoToEntryAtOffset(1);
2282 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
2283 // The actual cross-navigation is suspended until the current RVH tells us
2284 // it unloaded, simulate that.
2285 contents()->ProceedWithCrossSiteNavigation();
2286 message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
2287 ASSERT_TRUE(message != NULL);
2288 ViewMsg_Navigate::Read(message, &nav_params);
2289 EXPECT_EQ(url3, nav_params.a.url);
2290 process()->sink().ClearMessages();
2291
2292 // Make sure an extravagant history.go() doesn't break.
2293 contents()->OnGoToEntryAtOffset(120); // Out of bounds.
2294 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
2295 message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
2296 EXPECT_TRUE(message == NULL);
2297 }
2298
2299 // Test call to PruneAllButActive for the only entry.
2300 TEST_F(NavigationControllerTest, PruneAllButActiveForSingle) {
2301 NavigationControllerImpl& controller = controller_impl();
2302 const GURL url1("http://foo1");
2303 NavigateAndCommit(url1);
2304 controller.PruneAllButActive();
2305
2306 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
2307 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1);
2308 }
2309
2310 // Test call to PruneAllButActive for last entry.
2311 TEST_F(NavigationControllerTest, PruneAllButActiveForLast) {
2312 NavigationControllerImpl& controller = controller_impl();
2313 const GURL url1("http://foo/1");
2314 const GURL url2("http://foo/2");
2315 const GURL url3("http://foo/3");
2316
2317 NavigateAndCommit(url1);
2318 NavigateAndCommit(url2);
2319 NavigateAndCommit(url3);
2320 controller.GoBack();
2321 controller.GoBack();
2322 contents()->CommitPendingNavigation();
2323
2324 controller.PruneAllButActive();
2325
2326 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
2327 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url1);
2328 }
2329
2330 // Test call to PruneAllButActive for intermediate entry.
2331 TEST_F(NavigationControllerTest, PruneAllButActiveForIntermediate) {
2332 NavigationControllerImpl& controller = controller_impl();
2333 const GURL url1("http://foo/1");
2334 const GURL url2("http://foo/2");
2335 const GURL url3("http://foo/3");
2336
2337 NavigateAndCommit(url1);
2338 NavigateAndCommit(url2);
2339 NavigateAndCommit(url3);
2340 controller.GoBack();
2341 contents()->CommitPendingNavigation();
2342
2343 controller.PruneAllButActive();
2344
2345 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
2346 EXPECT_EQ(controller.GetEntryAtIndex(0)->GetURL(), url2);
2347 }
2348
2349 // Test call to PruneAllButActive for intermediate entry.
2350 TEST_F(NavigationControllerTest, PruneAllButActiveForPending) {
2351 NavigationControllerImpl& controller = controller_impl();
2352 const GURL url1("http://foo/1");
2353 const GURL url2("http://foo/2");
2354 const GURL url3("http://foo/3");
2355
2356 NavigateAndCommit(url1);
2357 NavigateAndCommit(url2);
2358 NavigateAndCommit(url3);
2359 controller.GoBack();
2360
2361 controller.PruneAllButActive();
2362
2363 EXPECT_EQ(0, controller.GetPendingEntryIndex());
2364 }
2365
2366 // Test call to PruneAllButActive for transient entry.
2367 TEST_F(NavigationControllerTest, PruneAllButActiveForTransient) {
2368 NavigationControllerImpl& controller = controller_impl();
2369 const GURL url0("http://foo/0");
2370 const GURL url1("http://foo/1");
2371 const GURL transient_url("http://foo/transient");
2372
2373 controller.LoadURL(
2374 url0, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
2375 test_rvh()->SendNavigate(0, url0);
2376 controller.LoadURL(
2377 url1, content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string());
2378 test_rvh()->SendNavigate(1, url1);
2379
2380 // Adding a transient with no pending entry.
2381 NavigationEntryImpl* transient_entry = new NavigationEntryImpl;
2382 transient_entry->SetURL(transient_url);
2383 controller.AddTransientEntry(transient_entry);
2384
2385 controller.PruneAllButActive();
2386
2387 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
2388 EXPECT_EQ(controller.GetTransientEntry()->GetURL(), transient_url);
2389 }
2390
2391 // Test to ensure that when we do a history navigation back to the current
2392 // committed page (e.g., going forward to a slow-loading page, then pressing
2393 // the back button), we just stop the navigation to prevent the throbber from
2394 // running continuously. Otherwise, the RenderViewHost forces the throbber to
2395 // start, but WebKit essentially ignores the navigation and never sends a
2396 // message to stop the throbber.
2397 TEST_F(NavigationControllerTest, StopOnHistoryNavigationToCurrentPage) {
2398 NavigationControllerImpl& controller = controller_impl();
2399 const GURL url0("http://foo/0");
2400 const GURL url1("http://foo/1");
2401
2402 NavigateAndCommit(url0);
2403 NavigateAndCommit(url1);
2404
2405 // Go back to the original page, then forward to the slow page, then back
2406 controller.GoBack();
2407 contents()->CommitPendingNavigation();
2408
2409 controller.GoForward();
2410 EXPECT_EQ(1, controller.GetPendingEntryIndex());
2411
2412 controller.GoBack();
2413 EXPECT_EQ(-1, controller.GetPendingEntryIndex());
2414 }
2415
2416 /* TODO(brettw) These test pass on my local machine but fail on the XP buildbot
2417 (but not Vista) cleaning up the directory after they run.
2418 This should be fixed.
2419
2420 // NavigationControllerHistoryTest ---------------------------------------------
2421
2422 class NavigationControllerHistoryTest : public NavigationControllerTest {
2423 public:
2424 NavigationControllerHistoryTest()
2425 : url0("http://foo1"),
2426 url1("http://foo1"),
2427 url2("http://foo1"),
2428 profile_manager_(NULL) {
2429 }
2430
2431 virtual ~NavigationControllerHistoryTest() {
2432 // Prevent our base class from deleting the profile since profile's
2433 // lifetime is managed by profile_manager_.
2434 STLDeleteElements(&windows_);
2435 }
2436
2437 // testing::Test overrides.
2438 virtual void SetUp() {
2439 NavigationControllerTest::SetUp();
2440
2441 // Force the session service to be created.
2442 SessionService* service = new SessionService(profile());
2443 SessionServiceFactory::SetForTestProfile(profile(), service);
2444 service->SetWindowType(window_id, Browser::TYPE_TABBED);
2445 service->SetWindowBounds(window_id, gfx::Rect(0, 1, 2, 3), false);
2446 service->SetTabIndexInWindow(window_id,
2447 controller.session_id(), 0);
2448 controller.SetWindowID(window_id);
2449
2450 session_helper_.set_service(service);
2451 }
2452
2453 virtual void TearDown() {
2454 // Release profile's reference to the session service. Otherwise the file
2455 // will still be open and we won't be able to delete the directory below.
2456 session_helper_.ReleaseService(); // profile owns this
2457 SessionServiceFactory::SetForTestProfile(profile(), NULL);
2458
2459 // Make sure we wait for history to shut down before continuing. The task
2460 // we add will cause our message loop to quit once it is destroyed.
2461 HistoryService* history =
2462 profile()->GetHistoryService(Profile::IMPLICIT_ACCESS);
2463 if (history) {
2464 history->SetOnBackendDestroyTask(MessageLoop::QuitClosure());
2465 MessageLoop::current()->Run();
2466 }
2467
2468 // Do normal cleanup before deleting the profile directory below.
2469 NavigationControllerTest::TearDown();
2470
2471 ASSERT_TRUE(file_util::Delete(test_dir_, true));
2472 ASSERT_FALSE(file_util::PathExists(test_dir_));
2473 }
2474
2475 // Deletes the current profile manager and creates a new one. Indirectly this
2476 // shuts down the history database and reopens it.
2477 void ReopenDatabase() {
2478 session_helper_.set_service(NULL);
2479 SessionServiceFactory::SetForTestProfile(profile(), NULL);
2480
2481 SessionService* service = new SessionService(profile());
2482 SessionServiceFactory::SetForTestProfile(profile(), service);
2483 session_helper_.set_service(service);
2484 }
2485
2486 void GetLastSession() {
2487 SessionServiceFactory::GetForProfile(profile())->TabClosed(
2488 controller.window_id(), controller.session_id(), false);
2489
2490 ReopenDatabase();
2491 Time close_time;
2492
2493 session_helper_.ReadWindows(&windows_);
2494 }
2495
2496 CancelableRequestConsumer consumer;
2497
2498 // URLs for testing.
2499 const GURL url0;
2500 const GURL url1;
2501 const GURL url2;
2502
2503 std::vector<SessionWindow*> windows_;
2504
2505 SessionID window_id;
2506
2507 SessionServiceTestHelper session_helper_;
2508
2509 private:
2510 ProfileManager* profile_manager_;
2511 FilePath test_dir_;
2512 };
2513
2514 // A basic test case. Navigates to a single url, and make sure the history
2515 // db matches.
2516 TEST_F(NavigationControllerHistoryTest, Basic) {
2517 NavigationControllerImpl& controller = controller_impl();
2518 controller.LoadURL(url0, GURL(), content::PAGE_TRANSITION_LINK);
2519 test_rvh()->SendNavigate(0, url0);
2520
2521 GetLastSession();
2522
2523 session_helper_.AssertSingleWindowWithSingleTab(windows_, 1);
2524 session_helper_.AssertTabEquals(0, 0, 1, *(windows_[0]->tabs[0]));
2525 TabNavigation nav1(0, url0, GURL(), string16(),
2526 webkit_glue::CreateHistoryStateForURL(url0),
2527 content::PAGE_TRANSITION_LINK);
2528 session_helper_.AssertNavigationEquals(nav1,
2529 windows_[0]->tabs[0]->navigations[0]);
2530 }
2531
2532 // Navigates to three urls, then goes back and make sure the history database
2533 // is in sync.
2534 TEST_F(NavigationControllerHistoryTest, NavigationThenBack) {
2535 NavigationControllerImpl& controller = controller_impl();
2536 test_rvh()->SendNavigate(0, url0);
2537 test_rvh()->SendNavigate(1, url1);
2538 test_rvh()->SendNavigate(2, url2);
2539
2540 controller.GoBack();
2541 test_rvh()->SendNavigate(1, url1);
2542
2543 GetLastSession();
2544
2545 session_helper_.AssertSingleWindowWithSingleTab(windows_, 3);
2546 session_helper_.AssertTabEquals(0, 1, 3, *(windows_[0]->tabs[0]));
2547
2548 TabNavigation nav(0, url0, GURL(), string16(),
2549 webkit_glue::CreateHistoryStateForURL(url0),
2550 content::PAGE_TRANSITION_LINK);
2551 session_helper_.AssertNavigationEquals(nav,
2552 windows_[0]->tabs[0]->navigations[0]);
2553 nav.set_url(url1);
2554 session_helper_.AssertNavigationEquals(nav,
2555 windows_[0]->tabs[0]->navigations[1]);
2556 nav.set_url(url2);
2557 session_helper_.AssertNavigationEquals(nav,
2558 windows_[0]->tabs[0]->navigations[2]);
2559 }
2560
2561 // Navigates to three urls, then goes back twice, then loads a new url.
2562 TEST_F(NavigationControllerHistoryTest, NavigationPruning) {
2563 NavigationControllerImpl& controller = controller_impl();
2564 test_rvh()->SendNavigate(0, url0);
2565 test_rvh()->SendNavigate(1, url1);
2566 test_rvh()->SendNavigate(2, url2);
2567
2568 controller.GoBack();
2569 test_rvh()->SendNavigate(1, url1);
2570
2571 controller.GoBack();
2572 test_rvh()->SendNavigate(0, url0);
2573
2574 test_rvh()->SendNavigate(3, url2);
2575
2576 // Now have url0, and url2.
2577
2578 GetLastSession();
2579
2580 session_helper_.AssertSingleWindowWithSingleTab(windows_, 2);
2581 session_helper_.AssertTabEquals(0, 1, 2, *(windows_[0]->tabs[0]));
2582
2583 TabNavigation nav(0, url0, GURL(), string16(),
2584 webkit_glue::CreateHistoryStateForURL(url0),
2585 content::PAGE_TRANSITION_LINK);
2586 session_helper_.AssertNavigationEquals(nav,
2587 windows_[0]->tabs[0]->navigations[0]);
2588 nav.set_url(url2);
2589 session_helper_.AssertNavigationEquals(nav,
2590 windows_[0]->tabs[0]->navigations[1]);
2591 }
2592 */
OLDNEW
« no previous file with comments | « content/browser/tab_contents/navigation_controller_impl.cc ('k') | content/browser/tab_contents/navigation_entry_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698