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

Side by Side Diff: chrome/browser/tab_contents/navigation_controller_unittest.cc

Issue 6537015: Start moving core pieces of Chrome multi-process code to src\content. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 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) 2010 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/path_service.h"
7 #include "base/scoped_ptr.h"
8 #include "base/stl_util-inl.h"
9 #include "base/string_util.h"
10 #include "base/utf_string_conversions.h"
11 #include "chrome/browser/profiles/profile_manager.h"
12 #include "chrome/browser/history/history.h"
13 #include "chrome/browser/renderer_host/site_instance.h"
14 #include "chrome/browser/renderer_host/test/test_render_view_host.h"
15 #include "chrome/browser/sessions/session_service.h"
16 #include "chrome/browser/sessions/session_service_test_helper.h"
17 #include "chrome/browser/sessions/session_types.h"
18 #include "chrome/browser/tab_contents/navigation_controller.h"
19 #include "chrome/browser/tab_contents/navigation_entry.h"
20 #include "chrome/browser/tab_contents/tab_contents.h"
21 #include "chrome/browser/tab_contents/tab_contents_delegate.h"
22 #include "chrome/browser/tab_contents/test_tab_contents.h"
23 #include "chrome/common/notification_registrar.h"
24 #include "chrome/common/render_messages.h"
25 #include "chrome/common/render_messages_params.h"
26 #include "chrome/test/test_notification_tracker.h"
27 #include "chrome/test/testing_profile.h"
28 #include "net/base/net_util.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "webkit/glue/webkit_glue.h"
31
32 using base::Time;
33
34 // NavigationControllerTest ----------------------------------------------------
35
36 class NavigationControllerTest : public RenderViewHostTestHarness {
37 public:
38 NavigationControllerTest() {}
39 };
40
41 // NavigationControllerHistoryTest ---------------------------------------------
42
43 class NavigationControllerHistoryTest : public NavigationControllerTest {
44 public:
45 NavigationControllerHistoryTest()
46 : url0("http://foo1"),
47 url1("http://foo1"),
48 url2("http://foo1"),
49 profile_manager_(NULL) {
50 }
51
52 virtual ~NavigationControllerHistoryTest() {
53 // Prevent our base class from deleting the profile since profile's
54 // lifetime is managed by profile_manager_.
55 STLDeleteElements(&windows_);
56 }
57
58 // testing::Test overrides.
59 virtual void SetUp() {
60 NavigationControllerTest::SetUp();
61
62 // Force the session service to be created.
63 SessionService* service = new SessionService(profile());
64 profile()->set_session_service(service);
65 service->SetWindowType(window_id, Browser::TYPE_NORMAL);
66 service->SetWindowBounds(window_id, gfx::Rect(0, 1, 2, 3), false);
67 service->SetTabIndexInWindow(window_id,
68 controller().session_id(), 0);
69 controller().SetWindowID(window_id);
70
71 session_helper_.set_service(service);
72 }
73
74 virtual void TearDown() {
75 // Release profile's reference to the session service. Otherwise the file
76 // will still be open and we won't be able to delete the directory below.
77 profile()->set_session_service(NULL);
78 session_helper_.set_service(NULL);
79
80 // Make sure we wait for history to shut down before continuing. The task
81 // we add will cause our message loop to quit once it is destroyed.
82 HistoryService* history =
83 profile()->GetHistoryService(Profile::IMPLICIT_ACCESS);
84 if (history) {
85 history->SetOnBackendDestroyTask(new MessageLoop::QuitTask);
86 MessageLoop::current()->Run();
87 }
88
89 // Do normal cleanup before deleting the profile directory below.
90 NavigationControllerTest::TearDown();
91
92 ASSERT_TRUE(file_util::Delete(test_dir_, true));
93 ASSERT_FALSE(file_util::PathExists(test_dir_));
94 }
95
96 // Deletes the current profile manager and creates a new one. Indirectly this
97 // shuts down the history database and reopens it.
98 void ReopenDatabase() {
99 session_helper_.set_service(NULL);
100 profile()->set_session_service(NULL);
101
102 SessionService* service = new SessionService(profile());
103 profile()->set_session_service(service);
104 session_helper_.set_service(service);
105 }
106
107 void GetLastSession() {
108 profile()->GetSessionService()->TabClosed(controller().window_id(),
109 controller().session_id(),
110 false);
111
112 ReopenDatabase();
113 Time close_time;
114
115 session_helper_.ReadWindows(&windows_);
116 }
117
118 CancelableRequestConsumer consumer;
119
120 // URLs for testing.
121 const GURL url0;
122 const GURL url1;
123 const GURL url2;
124
125 std::vector<SessionWindow*> windows_;
126
127 SessionID window_id;
128
129 SessionServiceTestHelper session_helper_;
130
131 private:
132 ProfileManager* profile_manager_;
133 FilePath test_dir_;
134 };
135
136 void RegisterForAllNavNotifications(TestNotificationTracker* tracker,
137 NavigationController* controller) {
138 tracker->ListenFor(NotificationType::NAV_ENTRY_COMMITTED,
139 Source<NavigationController>(controller));
140 tracker->ListenFor(NotificationType::NAV_LIST_PRUNED,
141 Source<NavigationController>(controller));
142 tracker->ListenFor(NotificationType::NAV_ENTRY_CHANGED,
143 Source<NavigationController>(controller));
144 }
145
146 // -----------------------------------------------------------------------------
147
148 TEST_F(NavigationControllerTest, Defaults) {
149 EXPECT_FALSE(controller().pending_entry());
150 EXPECT_FALSE(controller().GetLastCommittedEntry());
151 EXPECT_EQ(controller().pending_entry_index(), -1);
152 EXPECT_EQ(controller().last_committed_entry_index(), -1);
153 EXPECT_EQ(controller().entry_count(), 0);
154 EXPECT_FALSE(controller().CanGoBack());
155 EXPECT_FALSE(controller().CanGoForward());
156 }
157
158 TEST_F(NavigationControllerTest, LoadURL) {
159 TestNotificationTracker notifications;
160 RegisterForAllNavNotifications(&notifications, &controller());
161
162 const GURL url1("http://foo1");
163 const GURL url2("http://foo2");
164
165 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
166 // Creating a pending notification should not have issued any of the
167 // notifications we're listening for.
168 EXPECT_EQ(0U, notifications.size());
169
170 // The load should now be pending.
171 EXPECT_EQ(controller().entry_count(), 0);
172 EXPECT_EQ(controller().last_committed_entry_index(), -1);
173 EXPECT_EQ(controller().pending_entry_index(), -1);
174 EXPECT_FALSE(controller().GetLastCommittedEntry());
175 EXPECT_TRUE(controller().pending_entry());
176 EXPECT_FALSE(controller().CanGoBack());
177 EXPECT_FALSE(controller().CanGoForward());
178 EXPECT_EQ(contents()->GetMaxPageID(), -1);
179
180 // We should have gotten no notifications from the preceeding checks.
181 EXPECT_EQ(0U, notifications.size());
182
183 rvh()->SendNavigate(0, url1);
184 EXPECT_TRUE(notifications.Check1AndReset(
185 NotificationType::NAV_ENTRY_COMMITTED));
186
187 // The load should now be committed.
188 EXPECT_EQ(controller().entry_count(), 1);
189 EXPECT_EQ(controller().last_committed_entry_index(), 0);
190 EXPECT_EQ(controller().pending_entry_index(), -1);
191 EXPECT_TRUE(controller().GetLastCommittedEntry());
192 EXPECT_FALSE(controller().pending_entry());
193 EXPECT_FALSE(controller().CanGoBack());
194 EXPECT_FALSE(controller().CanGoForward());
195 EXPECT_EQ(contents()->GetMaxPageID(), 0);
196
197 // Load another...
198 controller().LoadURL(url2, GURL(), PageTransition::TYPED);
199
200 // The load should now be pending.
201 EXPECT_EQ(controller().entry_count(), 1);
202 EXPECT_EQ(controller().last_committed_entry_index(), 0);
203 EXPECT_EQ(controller().pending_entry_index(), -1);
204 EXPECT_TRUE(controller().GetLastCommittedEntry());
205 EXPECT_TRUE(controller().pending_entry());
206 // TODO(darin): maybe this should really be true?
207 EXPECT_FALSE(controller().CanGoBack());
208 EXPECT_FALSE(controller().CanGoForward());
209 EXPECT_EQ(contents()->GetMaxPageID(), 0);
210
211 rvh()->SendNavigate(1, url2);
212 EXPECT_TRUE(notifications.Check1AndReset(
213 NotificationType::NAV_ENTRY_COMMITTED));
214
215 // The load should now be committed.
216 EXPECT_EQ(controller().entry_count(), 2);
217 EXPECT_EQ(controller().last_committed_entry_index(), 1);
218 EXPECT_EQ(controller().pending_entry_index(), -1);
219 EXPECT_TRUE(controller().GetLastCommittedEntry());
220 EXPECT_FALSE(controller().pending_entry());
221 EXPECT_TRUE(controller().CanGoBack());
222 EXPECT_FALSE(controller().CanGoForward());
223 EXPECT_EQ(contents()->GetMaxPageID(), 1);
224 }
225
226 // Tests what happens when the same page is loaded again. Should not create a
227 // new session history entry. This is what happens when you press enter in the
228 // URL bar to reload: a pending entry is created and then it is discarded when
229 // the load commits (because WebCore didn't actually make a new entry).
230 TEST_F(NavigationControllerTest, LoadURL_SamePage) {
231 TestNotificationTracker notifications;
232 RegisterForAllNavNotifications(&notifications, &controller());
233
234 const GURL url1("http://foo1");
235
236 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
237 EXPECT_EQ(0U, notifications.size());
238 rvh()->SendNavigate(0, url1);
239 EXPECT_TRUE(notifications.Check1AndReset(
240 NotificationType::NAV_ENTRY_COMMITTED));
241
242 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
243 EXPECT_EQ(0U, notifications.size());
244 rvh()->SendNavigate(0, url1);
245 EXPECT_TRUE(notifications.Check1AndReset(
246 NotificationType::NAV_ENTRY_COMMITTED));
247
248 // We should not have produced a new session history entry.
249 EXPECT_EQ(controller().entry_count(), 1);
250 EXPECT_EQ(controller().last_committed_entry_index(), 0);
251 EXPECT_EQ(controller().pending_entry_index(), -1);
252 EXPECT_TRUE(controller().GetLastCommittedEntry());
253 EXPECT_FALSE(controller().pending_entry());
254 EXPECT_FALSE(controller().CanGoBack());
255 EXPECT_FALSE(controller().CanGoForward());
256 }
257
258 // Tests loading a URL but discarding it before the load commits.
259 TEST_F(NavigationControllerTest, LoadURL_Discarded) {
260 TestNotificationTracker notifications;
261 RegisterForAllNavNotifications(&notifications, &controller());
262
263 const GURL url1("http://foo1");
264 const GURL url2("http://foo2");
265
266 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
267 EXPECT_EQ(0U, notifications.size());
268 rvh()->SendNavigate(0, url1);
269 EXPECT_TRUE(notifications.Check1AndReset(
270 NotificationType::NAV_ENTRY_COMMITTED));
271
272 controller().LoadURL(url2, GURL(), PageTransition::TYPED);
273 controller().DiscardNonCommittedEntries();
274 EXPECT_EQ(0U, notifications.size());
275
276 // Should not have produced a new session history entry.
277 EXPECT_EQ(controller().entry_count(), 1);
278 EXPECT_EQ(controller().last_committed_entry_index(), 0);
279 EXPECT_EQ(controller().pending_entry_index(), -1);
280 EXPECT_TRUE(controller().GetLastCommittedEntry());
281 EXPECT_FALSE(controller().pending_entry());
282 EXPECT_FALSE(controller().CanGoBack());
283 EXPECT_FALSE(controller().CanGoForward());
284 }
285
286 // Tests navigations that come in unrequested. This happens when the user
287 // navigates from the web page, and here we test that there is no pending entry.
288 TEST_F(NavigationControllerTest, LoadURL_NoPending) {
289 TestNotificationTracker notifications;
290 RegisterForAllNavNotifications(&notifications, &controller());
291
292 // First make an existing committed entry.
293 const GURL kExistingURL1("http://eh");
294 controller().LoadURL(kExistingURL1, GURL(),
295 PageTransition::TYPED);
296 rvh()->SendNavigate(0, kExistingURL1);
297 EXPECT_TRUE(notifications.Check1AndReset(
298 NotificationType::NAV_ENTRY_COMMITTED));
299
300 // Do a new navigation without making a pending one.
301 const GURL kNewURL("http://see");
302 rvh()->SendNavigate(99, kNewURL);
303
304 // There should no longer be any pending entry, and the third navigation we
305 // just made should be committed.
306 EXPECT_TRUE(notifications.Check1AndReset(
307 NotificationType::NAV_ENTRY_COMMITTED));
308 EXPECT_EQ(-1, controller().pending_entry_index());
309 EXPECT_EQ(1, controller().last_committed_entry_index());
310 EXPECT_EQ(kNewURL, controller().GetActiveEntry()->url());
311 }
312
313 // Tests navigating to a new URL when there is a new pending navigation that is
314 // not the one that just loaded. This will happen if the user types in a URL to
315 // somewhere slow, and then navigates the current page before the typed URL
316 // commits.
317 TEST_F(NavigationControllerTest, LoadURL_NewPending) {
318 TestNotificationTracker notifications;
319 RegisterForAllNavNotifications(&notifications, &controller());
320
321 // First make an existing committed entry.
322 const GURL kExistingURL1("http://eh");
323 controller().LoadURL(kExistingURL1, GURL(),
324 PageTransition::TYPED);
325 rvh()->SendNavigate(0, kExistingURL1);
326 EXPECT_TRUE(notifications.Check1AndReset(
327 NotificationType::NAV_ENTRY_COMMITTED));
328
329 // Make a pending entry to somewhere new.
330 const GURL kExistingURL2("http://bee");
331 controller().LoadURL(kExistingURL2, GURL(),
332 PageTransition::TYPED);
333 EXPECT_EQ(0U, notifications.size());
334
335 // Before that commits, do a new navigation.
336 const GURL kNewURL("http://see");
337 rvh()->SendNavigate(3, kNewURL);
338
339 // There should no longer be any pending entry, and the third navigation we
340 // just made should be committed.
341 EXPECT_TRUE(notifications.Check1AndReset(
342 NotificationType::NAV_ENTRY_COMMITTED));
343 EXPECT_EQ(-1, controller().pending_entry_index());
344 EXPECT_EQ(1, controller().last_committed_entry_index());
345 EXPECT_EQ(kNewURL, controller().GetActiveEntry()->url());
346 }
347
348 // Tests navigating to a new URL when there is a pending back/forward
349 // navigation. This will happen if the user hits back, but before that commits,
350 // they navigate somewhere new.
351 TEST_F(NavigationControllerTest, LoadURL_ExistingPending) {
352 TestNotificationTracker notifications;
353 RegisterForAllNavNotifications(&notifications, &controller());
354
355 // First make some history.
356 const GURL kExistingURL1("http://eh");
357 controller().LoadURL(kExistingURL1, GURL(),
358 PageTransition::TYPED);
359 rvh()->SendNavigate(0, kExistingURL1);
360 EXPECT_TRUE(notifications.Check1AndReset(
361 NotificationType::NAV_ENTRY_COMMITTED));
362
363 const GURL kExistingURL2("http://bee");
364 controller().LoadURL(kExistingURL2, GURL(),
365 PageTransition::TYPED);
366 rvh()->SendNavigate(1, kExistingURL2);
367 EXPECT_TRUE(notifications.Check1AndReset(
368 NotificationType::NAV_ENTRY_COMMITTED));
369
370 // Now make a pending back/forward navigation. The zeroth entry should be
371 // pending.
372 controller().GoBack();
373 EXPECT_EQ(0U, notifications.size());
374 EXPECT_EQ(0, controller().pending_entry_index());
375 EXPECT_EQ(1, controller().last_committed_entry_index());
376
377 // Before that commits, do a new navigation.
378 const GURL kNewURL("http://see");
379 NavigationController::LoadCommittedDetails details;
380 rvh()->SendNavigate(3, kNewURL);
381
382 // There should no longer be any pending entry, and the third navigation we
383 // just made should be committed.
384 EXPECT_TRUE(notifications.Check1AndReset(
385 NotificationType::NAV_ENTRY_COMMITTED));
386 EXPECT_EQ(-1, controller().pending_entry_index());
387 EXPECT_EQ(2, controller().last_committed_entry_index());
388 EXPECT_EQ(kNewURL, controller().GetActiveEntry()->url());
389 }
390
391 TEST_F(NavigationControllerTest, Reload) {
392 TestNotificationTracker notifications;
393 RegisterForAllNavNotifications(&notifications, &controller());
394
395 const GURL url1("http://foo1");
396
397 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
398 EXPECT_EQ(0U, notifications.size());
399 rvh()->SendNavigate(0, url1);
400 EXPECT_TRUE(notifications.Check1AndReset(
401 NotificationType::NAV_ENTRY_COMMITTED));
402
403 controller().Reload(true);
404 EXPECT_EQ(0U, notifications.size());
405
406 // The reload is pending.
407 EXPECT_EQ(controller().entry_count(), 1);
408 EXPECT_EQ(controller().last_committed_entry_index(), 0);
409 EXPECT_EQ(controller().pending_entry_index(), 0);
410 EXPECT_TRUE(controller().GetLastCommittedEntry());
411 EXPECT_TRUE(controller().pending_entry());
412 EXPECT_FALSE(controller().CanGoBack());
413 EXPECT_FALSE(controller().CanGoForward());
414
415 rvh()->SendNavigate(0, url1);
416 EXPECT_TRUE(notifications.Check1AndReset(
417 NotificationType::NAV_ENTRY_COMMITTED));
418
419 // Now the reload is committed.
420 EXPECT_EQ(controller().entry_count(), 1);
421 EXPECT_EQ(controller().last_committed_entry_index(), 0);
422 EXPECT_EQ(controller().pending_entry_index(), -1);
423 EXPECT_TRUE(controller().GetLastCommittedEntry());
424 EXPECT_FALSE(controller().pending_entry());
425 EXPECT_FALSE(controller().CanGoBack());
426 EXPECT_FALSE(controller().CanGoForward());
427 }
428
429 // Tests what happens when a reload navigation produces a new page.
430 TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) {
431 TestNotificationTracker notifications;
432 RegisterForAllNavNotifications(&notifications, &controller());
433
434 const GURL url1("http://foo1");
435 const GURL url2("http://foo2");
436
437 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
438 rvh()->SendNavigate(0, url1);
439 EXPECT_TRUE(notifications.Check1AndReset(
440 NotificationType::NAV_ENTRY_COMMITTED));
441
442 controller().Reload(true);
443 EXPECT_EQ(0U, notifications.size());
444
445 rvh()->SendNavigate(1, url2);
446 EXPECT_TRUE(notifications.Check1AndReset(
447 NotificationType::NAV_ENTRY_COMMITTED));
448
449 // Now the reload is committed.
450 EXPECT_EQ(controller().entry_count(), 2);
451 EXPECT_EQ(controller().last_committed_entry_index(), 1);
452 EXPECT_EQ(controller().pending_entry_index(), -1);
453 EXPECT_TRUE(controller().GetLastCommittedEntry());
454 EXPECT_FALSE(controller().pending_entry());
455 EXPECT_TRUE(controller().CanGoBack());
456 EXPECT_FALSE(controller().CanGoForward());
457 }
458
459 // Tests what happens when we navigate back successfully
460 TEST_F(NavigationControllerTest, Back) {
461 TestNotificationTracker notifications;
462 RegisterForAllNavNotifications(&notifications, &controller());
463
464 const GURL url1("http://foo1");
465 rvh()->SendNavigate(0, url1);
466 EXPECT_TRUE(notifications.Check1AndReset(
467 NotificationType::NAV_ENTRY_COMMITTED));
468
469 const GURL url2("http://foo2");
470 rvh()->SendNavigate(1, url2);
471 EXPECT_TRUE(notifications.Check1AndReset(
472 NotificationType::NAV_ENTRY_COMMITTED));
473
474 controller().GoBack();
475 EXPECT_EQ(0U, notifications.size());
476
477 // We should now have a pending navigation to go back.
478 EXPECT_EQ(controller().entry_count(), 2);
479 EXPECT_EQ(controller().last_committed_entry_index(), 1);
480 EXPECT_EQ(controller().pending_entry_index(), 0);
481 EXPECT_TRUE(controller().GetLastCommittedEntry());
482 EXPECT_TRUE(controller().pending_entry());
483 EXPECT_FALSE(controller().CanGoBack());
484 EXPECT_TRUE(controller().CanGoForward());
485
486 rvh()->SendNavigate(0, url2);
487 EXPECT_TRUE(notifications.Check1AndReset(
488 NotificationType::NAV_ENTRY_COMMITTED));
489
490 // The back navigation completed successfully.
491 EXPECT_EQ(controller().entry_count(), 2);
492 EXPECT_EQ(controller().last_committed_entry_index(), 0);
493 EXPECT_EQ(controller().pending_entry_index(), -1);
494 EXPECT_TRUE(controller().GetLastCommittedEntry());
495 EXPECT_FALSE(controller().pending_entry());
496 EXPECT_FALSE(controller().CanGoBack());
497 EXPECT_TRUE(controller().CanGoForward());
498 }
499
500 // Tests what happens when a back navigation produces a new page.
501 TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
502 TestNotificationTracker notifications;
503 RegisterForAllNavNotifications(&notifications, &controller());
504
505 const GURL url1("http://foo1");
506 const GURL url2("http://foo2");
507 const GURL url3("http://foo3");
508
509 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
510 rvh()->SendNavigate(0, url1);
511 EXPECT_TRUE(notifications.Check1AndReset(
512 NotificationType::NAV_ENTRY_COMMITTED));
513
514 controller().LoadURL(url2, GURL(), PageTransition::TYPED);
515 rvh()->SendNavigate(1, url2);
516 EXPECT_TRUE(notifications.Check1AndReset(
517 NotificationType::NAV_ENTRY_COMMITTED));
518
519 controller().GoBack();
520 EXPECT_EQ(0U, notifications.size());
521
522 // We should now have a pending navigation to go back.
523 EXPECT_EQ(controller().entry_count(), 2);
524 EXPECT_EQ(controller().last_committed_entry_index(), 1);
525 EXPECT_EQ(controller().pending_entry_index(), 0);
526 EXPECT_TRUE(controller().GetLastCommittedEntry());
527 EXPECT_TRUE(controller().pending_entry());
528 EXPECT_FALSE(controller().CanGoBack());
529 EXPECT_TRUE(controller().CanGoForward());
530
531 rvh()->SendNavigate(2, url3);
532 EXPECT_TRUE(notifications.Check1AndReset(
533 NotificationType::NAV_ENTRY_COMMITTED));
534
535 // The back navigation resulted in a completely new navigation.
536 // TODO(darin): perhaps this behavior will be confusing to users?
537 EXPECT_EQ(controller().entry_count(), 3);
538 EXPECT_EQ(controller().last_committed_entry_index(), 2);
539 EXPECT_EQ(controller().pending_entry_index(), -1);
540 EXPECT_TRUE(controller().GetLastCommittedEntry());
541 EXPECT_FALSE(controller().pending_entry());
542 EXPECT_TRUE(controller().CanGoBack());
543 EXPECT_FALSE(controller().CanGoForward());
544 }
545
546 // Receives a back message when there is a new pending navigation entry.
547 TEST_F(NavigationControllerTest, Back_NewPending) {
548 TestNotificationTracker notifications;
549 RegisterForAllNavNotifications(&notifications, &controller());
550
551 const GURL kUrl1("http://foo1");
552 const GURL kUrl2("http://foo2");
553 const GURL kUrl3("http://foo3");
554
555 // First navigate two places so we have some back history.
556 rvh()->SendNavigate(0, kUrl1);
557 EXPECT_TRUE(notifications.Check1AndReset(
558 NotificationType::NAV_ENTRY_COMMITTED));
559
560 // controller().LoadURL(kUrl2, PageTransition::TYPED);
561 rvh()->SendNavigate(1, kUrl2);
562 EXPECT_TRUE(notifications.Check1AndReset(
563 NotificationType::NAV_ENTRY_COMMITTED));
564
565 // Now start a new pending navigation and go back before it commits.
566 controller().LoadURL(kUrl3, GURL(), PageTransition::TYPED);
567 EXPECT_EQ(-1, controller().pending_entry_index());
568 EXPECT_EQ(kUrl3, controller().pending_entry()->url());
569 controller().GoBack();
570
571 // The pending navigation should now be the "back" item and the new one
572 // should be gone.
573 EXPECT_EQ(0, controller().pending_entry_index());
574 EXPECT_EQ(kUrl1, controller().pending_entry()->url());
575 }
576
577 // Receives a back message when there is a different renavigation already
578 // pending.
579 TEST_F(NavigationControllerTest, Back_OtherBackPending) {
580 const GURL kUrl1("http://foo/1");
581 const GURL kUrl2("http://foo/2");
582 const GURL kUrl3("http://foo/3");
583
584 // First navigate three places so we have some back history.
585 rvh()->SendNavigate(0, kUrl1);
586 rvh()->SendNavigate(1, kUrl2);
587 rvh()->SendNavigate(2, kUrl3);
588
589 // With nothing pending, say we get a navigation to the second entry.
590 rvh()->SendNavigate(1, kUrl2);
591
592 // We know all the entries have the same site instance, so we can just grab
593 // a random one for looking up other entries.
594 SiteInstance* site_instance =
595 controller().GetLastCommittedEntry()->site_instance();
596
597 // That second URL should be the last committed and it should have gotten the
598 // new title.
599 EXPECT_EQ(kUrl2, controller().GetEntryWithPageID(site_instance, 1)->url());
600 EXPECT_EQ(1, controller().last_committed_entry_index());
601 EXPECT_EQ(-1, controller().pending_entry_index());
602
603 // Now go forward to the last item again and say it was committed.
604 controller().GoForward();
605 rvh()->SendNavigate(2, kUrl3);
606
607 // Now start going back one to the second page. It will be pending.
608 controller().GoBack();
609 EXPECT_EQ(1, controller().pending_entry_index());
610 EXPECT_EQ(2, controller().last_committed_entry_index());
611
612 // Not synthesize a totally new back event to the first page. This will not
613 // match the pending one.
614 rvh()->SendNavigate(0, kUrl1);
615
616 // The navigation should not have affected the pending entry.
617 EXPECT_EQ(1, controller().pending_entry_index());
618
619 // But the navigated entry should be the last committed.
620 EXPECT_EQ(0, controller().last_committed_entry_index());
621 EXPECT_EQ(kUrl1, controller().GetLastCommittedEntry()->url());
622 }
623
624 // Tests what happens when we navigate forward successfully.
625 TEST_F(NavigationControllerTest, Forward) {
626 TestNotificationTracker notifications;
627 RegisterForAllNavNotifications(&notifications, &controller());
628
629 const GURL url1("http://foo1");
630 const GURL url2("http://foo2");
631
632 rvh()->SendNavigate(0, url1);
633 EXPECT_TRUE(notifications.Check1AndReset(
634 NotificationType::NAV_ENTRY_COMMITTED));
635
636 rvh()->SendNavigate(1, url2);
637 EXPECT_TRUE(notifications.Check1AndReset(
638 NotificationType::NAV_ENTRY_COMMITTED));
639
640 controller().GoBack();
641 rvh()->SendNavigate(0, url1);
642 EXPECT_TRUE(notifications.Check1AndReset(
643 NotificationType::NAV_ENTRY_COMMITTED));
644
645 controller().GoForward();
646
647 // We should now have a pending navigation to go forward.
648 EXPECT_EQ(controller().entry_count(), 2);
649 EXPECT_EQ(controller().last_committed_entry_index(), 0);
650 EXPECT_EQ(controller().pending_entry_index(), 1);
651 EXPECT_TRUE(controller().GetLastCommittedEntry());
652 EXPECT_TRUE(controller().pending_entry());
653 EXPECT_TRUE(controller().CanGoBack());
654 EXPECT_FALSE(controller().CanGoForward());
655
656 rvh()->SendNavigate(1, url2);
657 EXPECT_TRUE(notifications.Check1AndReset(
658 NotificationType::NAV_ENTRY_COMMITTED));
659
660 // The forward navigation completed successfully.
661 EXPECT_EQ(controller().entry_count(), 2);
662 EXPECT_EQ(controller().last_committed_entry_index(), 1);
663 EXPECT_EQ(controller().pending_entry_index(), -1);
664 EXPECT_TRUE(controller().GetLastCommittedEntry());
665 EXPECT_FALSE(controller().pending_entry());
666 EXPECT_TRUE(controller().CanGoBack());
667 EXPECT_FALSE(controller().CanGoForward());
668 }
669
670 // Tests what happens when a forward navigation produces a new page.
671 TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
672 TestNotificationTracker notifications;
673 RegisterForAllNavNotifications(&notifications, &controller());
674
675 const GURL url1("http://foo1");
676 const GURL url2("http://foo2");
677 const GURL url3("http://foo3");
678
679 rvh()->SendNavigate(0, url1);
680 EXPECT_TRUE(notifications.Check1AndReset(
681 NotificationType::NAV_ENTRY_COMMITTED));
682 rvh()->SendNavigate(1, url2);
683 EXPECT_TRUE(notifications.Check1AndReset(
684 NotificationType::NAV_ENTRY_COMMITTED));
685
686 controller().GoBack();
687 rvh()->SendNavigate(0, url1);
688 EXPECT_TRUE(notifications.Check1AndReset(
689 NotificationType::NAV_ENTRY_COMMITTED));
690
691 controller().GoForward();
692 EXPECT_EQ(0U, notifications.size());
693
694 // Should now have a pending navigation to go forward.
695 EXPECT_EQ(controller().entry_count(), 2);
696 EXPECT_EQ(controller().last_committed_entry_index(), 0);
697 EXPECT_EQ(controller().pending_entry_index(), 1);
698 EXPECT_TRUE(controller().GetLastCommittedEntry());
699 EXPECT_TRUE(controller().pending_entry());
700 EXPECT_TRUE(controller().CanGoBack());
701 EXPECT_FALSE(controller().CanGoForward());
702
703 rvh()->SendNavigate(2, url3);
704 EXPECT_TRUE(notifications.Check2AndReset(
705 NotificationType::NAV_LIST_PRUNED,
706 NotificationType::NAV_ENTRY_COMMITTED));
707
708 EXPECT_EQ(controller().entry_count(), 2);
709 EXPECT_EQ(controller().last_committed_entry_index(), 1);
710 EXPECT_EQ(controller().pending_entry_index(), -1);
711 EXPECT_TRUE(controller().GetLastCommittedEntry());
712 EXPECT_FALSE(controller().pending_entry());
713 EXPECT_TRUE(controller().CanGoBack());
714 EXPECT_FALSE(controller().CanGoForward());
715 }
716
717 // Two consequent navigation for the same URL entered in should be considered
718 // as SAME_PAGE navigation even when we are redirected to some other page.
719 TEST_F(NavigationControllerTest, Redirect) {
720 TestNotificationTracker notifications;
721 RegisterForAllNavNotifications(&notifications, &controller());
722
723 const GURL url1("http://foo1");
724 const GURL url2("http://foo2"); // Redirection target
725
726 // First request
727 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
728
729 EXPECT_EQ(0U, notifications.size());
730 rvh()->SendNavigate(0, url2);
731 EXPECT_TRUE(notifications.Check1AndReset(
732 NotificationType::NAV_ENTRY_COMMITTED));
733
734 // Second request
735 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
736
737 EXPECT_TRUE(controller().pending_entry());
738 EXPECT_EQ(controller().pending_entry_index(), -1);
739 EXPECT_EQ(url1, controller().GetActiveEntry()->url());
740
741 ViewHostMsg_FrameNavigate_Params params;
742 params.page_id = 0;
743 params.url = url2;
744 params.transition = PageTransition::SERVER_REDIRECT;
745 params.redirects.push_back(GURL("http://foo1"));
746 params.redirects.push_back(GURL("http://foo2"));
747 params.should_update_history = false;
748 params.gesture = NavigationGestureAuto;
749 params.is_post = false;
750
751 NavigationController::LoadCommittedDetails details;
752
753 EXPECT_EQ(0U, notifications.size());
754 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
755 EXPECT_TRUE(notifications.Check1AndReset(
756 NotificationType::NAV_ENTRY_COMMITTED));
757
758 EXPECT_TRUE(details.type == NavigationType::SAME_PAGE);
759 EXPECT_EQ(controller().entry_count(), 1);
760 EXPECT_EQ(controller().last_committed_entry_index(), 0);
761 EXPECT_TRUE(controller().GetLastCommittedEntry());
762 EXPECT_EQ(controller().pending_entry_index(), -1);
763 EXPECT_FALSE(controller().pending_entry());
764 EXPECT_EQ(url2, controller().GetActiveEntry()->url());
765
766 EXPECT_FALSE(controller().CanGoBack());
767 EXPECT_FALSE(controller().CanGoForward());
768 }
769
770 // Similar to Redirect above, but the first URL is requested by POST,
771 // the second URL is requested by GET. NavigationEntry::has_post_data_
772 // must be cleared. http://crbug.com/21245
773 TEST_F(NavigationControllerTest, PostThenRedirect) {
774 TestNotificationTracker notifications;
775 RegisterForAllNavNotifications(&notifications, &controller());
776
777 const GURL url1("http://foo1");
778 const GURL url2("http://foo2"); // Redirection target
779
780 // First request as POST
781 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
782 controller().GetActiveEntry()->set_has_post_data(true);
783
784 EXPECT_EQ(0U, notifications.size());
785 rvh()->SendNavigate(0, url2);
786 EXPECT_TRUE(notifications.Check1AndReset(
787 NotificationType::NAV_ENTRY_COMMITTED));
788
789 // Second request
790 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
791
792 EXPECT_TRUE(controller().pending_entry());
793 EXPECT_EQ(controller().pending_entry_index(), -1);
794 EXPECT_EQ(url1, controller().GetActiveEntry()->url());
795
796 ViewHostMsg_FrameNavigate_Params params;
797 params.page_id = 0;
798 params.url = url2;
799 params.transition = PageTransition::SERVER_REDIRECT;
800 params.redirects.push_back(GURL("http://foo1"));
801 params.redirects.push_back(GURL("http://foo2"));
802 params.should_update_history = false;
803 params.gesture = NavigationGestureAuto;
804 params.is_post = false;
805
806 NavigationController::LoadCommittedDetails details;
807
808 EXPECT_EQ(0U, notifications.size());
809 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
810 EXPECT_TRUE(notifications.Check1AndReset(
811 NotificationType::NAV_ENTRY_COMMITTED));
812
813 EXPECT_TRUE(details.type == NavigationType::SAME_PAGE);
814 EXPECT_EQ(controller().entry_count(), 1);
815 EXPECT_EQ(controller().last_committed_entry_index(), 0);
816 EXPECT_TRUE(controller().GetLastCommittedEntry());
817 EXPECT_EQ(controller().pending_entry_index(), -1);
818 EXPECT_FALSE(controller().pending_entry());
819 EXPECT_EQ(url2, controller().GetActiveEntry()->url());
820 EXPECT_FALSE(controller().GetActiveEntry()->has_post_data());
821
822 EXPECT_FALSE(controller().CanGoBack());
823 EXPECT_FALSE(controller().CanGoForward());
824 }
825
826 // A redirect right off the bat should be a NEW_PAGE.
827 TEST_F(NavigationControllerTest, ImmediateRedirect) {
828 TestNotificationTracker notifications;
829 RegisterForAllNavNotifications(&notifications, &controller());
830
831 const GURL url1("http://foo1");
832 const GURL url2("http://foo2"); // Redirection target
833
834 // First request
835 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
836
837 EXPECT_TRUE(controller().pending_entry());
838 EXPECT_EQ(controller().pending_entry_index(), -1);
839 EXPECT_EQ(url1, controller().GetActiveEntry()->url());
840
841 ViewHostMsg_FrameNavigate_Params params;
842 params.page_id = 0;
843 params.url = url2;
844 params.transition = PageTransition::SERVER_REDIRECT;
845 params.redirects.push_back(GURL("http://foo1"));
846 params.redirects.push_back(GURL("http://foo2"));
847 params.should_update_history = false;
848 params.gesture = NavigationGestureAuto;
849 params.is_post = false;
850
851 NavigationController::LoadCommittedDetails details;
852
853 EXPECT_EQ(0U, notifications.size());
854 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
855 EXPECT_TRUE(notifications.Check1AndReset(
856 NotificationType::NAV_ENTRY_COMMITTED));
857
858 EXPECT_TRUE(details.type == NavigationType::NEW_PAGE);
859 EXPECT_EQ(controller().entry_count(), 1);
860 EXPECT_EQ(controller().last_committed_entry_index(), 0);
861 EXPECT_TRUE(controller().GetLastCommittedEntry());
862 EXPECT_EQ(controller().pending_entry_index(), -1);
863 EXPECT_FALSE(controller().pending_entry());
864 EXPECT_EQ(url2, controller().GetActiveEntry()->url());
865
866 EXPECT_FALSE(controller().CanGoBack());
867 EXPECT_FALSE(controller().CanGoForward());
868 }
869
870 // Tests navigation via link click within a subframe. A new navigation entry
871 // should be created.
872 TEST_F(NavigationControllerTest, NewSubframe) {
873 TestNotificationTracker notifications;
874 RegisterForAllNavNotifications(&notifications, &controller());
875
876 const GURL url1("http://foo1");
877 rvh()->SendNavigate(0, url1);
878 EXPECT_TRUE(notifications.Check1AndReset(
879 NotificationType::NAV_ENTRY_COMMITTED));
880
881 const GURL url2("http://foo2");
882 ViewHostMsg_FrameNavigate_Params params;
883 params.page_id = 1;
884 params.url = url2;
885 params.transition = PageTransition::MANUAL_SUBFRAME;
886 params.should_update_history = false;
887 params.gesture = NavigationGestureUser;
888 params.is_post = false;
889
890 NavigationController::LoadCommittedDetails details;
891 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
892 EXPECT_TRUE(notifications.Check1AndReset(
893 NotificationType::NAV_ENTRY_COMMITTED));
894 EXPECT_EQ(url1, details.previous_url);
895 EXPECT_FALSE(details.is_auto);
896 EXPECT_FALSE(details.is_in_page);
897 EXPECT_FALSE(details.is_main_frame);
898
899 // The new entry should be appended.
900 EXPECT_EQ(2, controller().entry_count());
901
902 // New entry should refer to the new page, but the old URL (entries only
903 // reflect the toplevel URL).
904 EXPECT_EQ(url1, details.entry->url());
905 EXPECT_EQ(params.page_id, details.entry->page_id());
906 }
907
908 // Some pages create a popup, then write an iframe into it. This causes a
909 // subframe navigation without having any committed entry. Such navigations
910 // just get thrown on the ground, but we shouldn't crash.
911 TEST_F(NavigationControllerTest, SubframeOnEmptyPage) {
912 TestNotificationTracker notifications;
913 RegisterForAllNavNotifications(&notifications, &controller());
914
915 // Navigation controller currently has no entries.
916 const GURL url("http://foo2");
917 ViewHostMsg_FrameNavigate_Params params;
918 params.page_id = 1;
919 params.url = url;
920 params.transition = PageTransition::AUTO_SUBFRAME;
921 params.should_update_history = false;
922 params.gesture = NavigationGestureAuto;
923 params.is_post = false;
924
925 NavigationController::LoadCommittedDetails details;
926 EXPECT_FALSE(controller().RendererDidNavigate(params, 0, &details));
927 EXPECT_EQ(0U, notifications.size());
928 }
929
930 // Auto subframes are ones the page loads automatically like ads. They should
931 // not create new navigation entries.
932 TEST_F(NavigationControllerTest, AutoSubframe) {
933 TestNotificationTracker notifications;
934 RegisterForAllNavNotifications(&notifications, &controller());
935
936 const GURL url1("http://foo1");
937 rvh()->SendNavigate(0, url1);
938 EXPECT_TRUE(notifications.Check1AndReset(
939 NotificationType::NAV_ENTRY_COMMITTED));
940
941 const GURL url2("http://foo2");
942 ViewHostMsg_FrameNavigate_Params params;
943 params.page_id = 0;
944 params.url = url2;
945 params.transition = PageTransition::AUTO_SUBFRAME;
946 params.should_update_history = false;
947 params.gesture = NavigationGestureUser;
948 params.is_post = false;
949
950 // Navigating should do nothing.
951 NavigationController::LoadCommittedDetails details;
952 EXPECT_FALSE(controller().RendererDidNavigate(params, 0, &details));
953 EXPECT_EQ(0U, notifications.size());
954
955 // There should still be only one entry.
956 EXPECT_EQ(1, controller().entry_count());
957 }
958
959 // Tests navigation and then going back to a subframe navigation.
960 TEST_F(NavigationControllerTest, BackSubframe) {
961 TestNotificationTracker notifications;
962 RegisterForAllNavNotifications(&notifications, &controller());
963
964 // Main page.
965 const GURL url1("http://foo1");
966 rvh()->SendNavigate(0, url1);
967 EXPECT_TRUE(notifications.Check1AndReset(
968 NotificationType::NAV_ENTRY_COMMITTED));
969
970 // First manual subframe navigation.
971 const GURL url2("http://foo2");
972 ViewHostMsg_FrameNavigate_Params params;
973 params.page_id = 1;
974 params.url = url2;
975 params.transition = PageTransition::MANUAL_SUBFRAME;
976 params.should_update_history = false;
977 params.gesture = NavigationGestureUser;
978 params.is_post = false;
979
980 // This should generate a new entry.
981 NavigationController::LoadCommittedDetails details;
982 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
983 EXPECT_TRUE(notifications.Check1AndReset(
984 NotificationType::NAV_ENTRY_COMMITTED));
985 EXPECT_EQ(2, controller().entry_count());
986
987 // Second manual subframe navigation should also make a new entry.
988 const GURL url3("http://foo3");
989 params.page_id = 2;
990 params.url = url3;
991 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
992 EXPECT_TRUE(notifications.Check1AndReset(
993 NotificationType::NAV_ENTRY_COMMITTED));
994 EXPECT_EQ(3, controller().entry_count());
995 EXPECT_EQ(2, controller().GetCurrentEntryIndex());
996
997 // Go back one.
998 controller().GoBack();
999 params.url = url2;
1000 params.page_id = 1;
1001 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
1002 EXPECT_TRUE(notifications.Check1AndReset(
1003 NotificationType::NAV_ENTRY_COMMITTED));
1004 EXPECT_EQ(3, controller().entry_count());
1005 EXPECT_EQ(1, controller().GetCurrentEntryIndex());
1006
1007 // Go back one more.
1008 controller().GoBack();
1009 params.url = url1;
1010 params.page_id = 0;
1011 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
1012 EXPECT_TRUE(notifications.Check1AndReset(
1013 NotificationType::NAV_ENTRY_COMMITTED));
1014 EXPECT_EQ(3, controller().entry_count());
1015 EXPECT_EQ(0, controller().GetCurrentEntryIndex());
1016 }
1017
1018 TEST_F(NavigationControllerTest, LinkClick) {
1019 TestNotificationTracker notifications;
1020 RegisterForAllNavNotifications(&notifications, &controller());
1021
1022 const GURL url1("http://foo1");
1023 const GURL url2("http://foo2");
1024
1025 rvh()->SendNavigate(0, url1);
1026 EXPECT_TRUE(notifications.Check1AndReset(
1027 NotificationType::NAV_ENTRY_COMMITTED));
1028
1029 rvh()->SendNavigate(1, url2);
1030 EXPECT_TRUE(notifications.Check1AndReset(
1031 NotificationType::NAV_ENTRY_COMMITTED));
1032
1033 // Should not have produced a new session history entry.
1034 EXPECT_EQ(controller().entry_count(), 2);
1035 EXPECT_EQ(controller().last_committed_entry_index(), 1);
1036 EXPECT_EQ(controller().pending_entry_index(), -1);
1037 EXPECT_TRUE(controller().GetLastCommittedEntry());
1038 EXPECT_FALSE(controller().pending_entry());
1039 EXPECT_TRUE(controller().CanGoBack());
1040 EXPECT_FALSE(controller().CanGoForward());
1041 }
1042
1043 TEST_F(NavigationControllerTest, InPage) {
1044 TestNotificationTracker notifications;
1045 RegisterForAllNavNotifications(&notifications, &controller());
1046
1047 // Main page.
1048 const GURL url1("http://foo");
1049 rvh()->SendNavigate(0, url1);
1050 EXPECT_TRUE(notifications.Check1AndReset(
1051 NotificationType::NAV_ENTRY_COMMITTED));
1052
1053 // First navigation.
1054 const GURL url2("http://foo#a");
1055 ViewHostMsg_FrameNavigate_Params params;
1056 params.page_id = 1;
1057 params.url = url2;
1058 params.transition = PageTransition::LINK;
1059 params.should_update_history = false;
1060 params.gesture = NavigationGestureUser;
1061 params.is_post = false;
1062
1063 // This should generate a new entry.
1064 NavigationController::LoadCommittedDetails details;
1065 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
1066 EXPECT_TRUE(notifications.Check1AndReset(
1067 NotificationType::NAV_ENTRY_COMMITTED));
1068 EXPECT_TRUE(details.is_in_page);
1069 EXPECT_FALSE(details.did_replace_entry);
1070 EXPECT_EQ(2, controller().entry_count());
1071
1072 // Go back one.
1073 ViewHostMsg_FrameNavigate_Params back_params(params);
1074 controller().GoBack();
1075 back_params.url = url1;
1076 back_params.page_id = 0;
1077 EXPECT_TRUE(controller().RendererDidNavigate(back_params, 0, &details));
1078 EXPECT_TRUE(notifications.Check1AndReset(
1079 NotificationType::NAV_ENTRY_COMMITTED));
1080 // is_in_page is false in that case but should be true.
1081 // See comment in AreURLsInPageNavigation() in navigation_controller.cc
1082 // EXPECT_TRUE(details.is_in_page);
1083 EXPECT_EQ(2, controller().entry_count());
1084 EXPECT_EQ(0, controller().GetCurrentEntryIndex());
1085 EXPECT_EQ(back_params.url, controller().GetActiveEntry()->url());
1086
1087 // Go forward
1088 ViewHostMsg_FrameNavigate_Params forward_params(params);
1089 controller().GoForward();
1090 forward_params.url = url2;
1091 forward_params.page_id = 1;
1092 EXPECT_TRUE(controller().RendererDidNavigate(forward_params, 0, &details));
1093 EXPECT_TRUE(notifications.Check1AndReset(
1094 NotificationType::NAV_ENTRY_COMMITTED));
1095 EXPECT_TRUE(details.is_in_page);
1096 EXPECT_EQ(2, controller().entry_count());
1097 EXPECT_EQ(1, controller().GetCurrentEntryIndex());
1098 EXPECT_EQ(forward_params.url,
1099 controller().GetActiveEntry()->url());
1100
1101 // Now go back and forward again. This is to work around a bug where we would
1102 // compare the incoming URL with the last committed entry rather than the
1103 // one identified by an existing page ID. This would result in the second URL
1104 // losing the reference fragment when you navigate away from it and then back.
1105 controller().GoBack();
1106 EXPECT_TRUE(controller().RendererDidNavigate(back_params, 0, &details));
1107 controller().GoForward();
1108 EXPECT_TRUE(controller().RendererDidNavigate(forward_params, 0, &details));
1109 EXPECT_EQ(forward_params.url,
1110 controller().GetActiveEntry()->url());
1111
1112 // Finally, navigate to an unrelated URL to make sure in_page is not sticky.
1113 const GURL url3("http://bar");
1114 params.page_id = 2;
1115 params.url = url3;
1116 notifications.Reset();
1117 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
1118 EXPECT_TRUE(notifications.Check1AndReset(
1119 NotificationType::NAV_ENTRY_COMMITTED));
1120 EXPECT_FALSE(details.is_in_page);
1121 }
1122
1123 TEST_F(NavigationControllerTest, InPage_Replace) {
1124 TestNotificationTracker notifications;
1125 RegisterForAllNavNotifications(&notifications, &controller());
1126
1127 // Main page.
1128 const GURL url1("http://foo");
1129 rvh()->SendNavigate(0, url1);
1130 EXPECT_TRUE(notifications.Check1AndReset(
1131 NotificationType::NAV_ENTRY_COMMITTED));
1132
1133 // First navigation.
1134 const GURL url2("http://foo#a");
1135 ViewHostMsg_FrameNavigate_Params params;
1136 params.page_id = 0; // Same page_id
1137 params.url = url2;
1138 params.transition = PageTransition::LINK;
1139 params.should_update_history = false;
1140 params.gesture = NavigationGestureUser;
1141 params.is_post = false;
1142
1143 // This should NOT generate a new entry.
1144 NavigationController::LoadCommittedDetails details;
1145 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
1146 EXPECT_TRUE(notifications.Check2AndReset(
1147 NotificationType::NAV_LIST_PRUNED,
1148 NotificationType::NAV_ENTRY_COMMITTED));
1149 EXPECT_TRUE(details.is_in_page);
1150 EXPECT_TRUE(details.did_replace_entry);
1151 EXPECT_EQ(1, controller().entry_count());
1152 }
1153
1154 // Tests for http://crbug.com/40395
1155 // Simulates this:
1156 // <script>
1157 // window.location.replace("#a");
1158 // window.location='http://foo3/';
1159 // </script>
1160 TEST_F(NavigationControllerTest, ClientRedirectAfterInPageNavigation) {
1161 TestNotificationTracker notifications;
1162 RegisterForAllNavNotifications(&notifications, &controller());
1163
1164 // Load an initial page.
1165 {
1166 const GURL url("http://foo/");
1167 rvh()->SendNavigate(0, url);
1168 EXPECT_TRUE(notifications.Check1AndReset(
1169 NotificationType::NAV_ENTRY_COMMITTED));
1170 }
1171
1172 // Navigate to a new page.
1173 {
1174 const GURL url("http://foo2/");
1175 rvh()->SendNavigate(1, url);
1176 controller().DocumentLoadedInFrame();
1177 EXPECT_TRUE(notifications.Check1AndReset(
1178 NotificationType::NAV_ENTRY_COMMITTED));
1179 }
1180
1181 // Navigate within the page.
1182 {
1183 const GURL url("http://foo2/#a");
1184 ViewHostMsg_FrameNavigate_Params params;
1185 params.page_id = 1; // Same page_id
1186 params.url = url;
1187 params.transition = PageTransition::LINK;
1188 params.redirects.push_back(url);
1189 params.should_update_history = true;
1190 params.gesture = NavigationGestureUnknown;
1191 params.is_post = false;
1192
1193 // This should NOT generate a new entry.
1194 NavigationController::LoadCommittedDetails details;
1195 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
1196 EXPECT_TRUE(notifications.Check2AndReset(
1197 NotificationType::NAV_LIST_PRUNED,
1198 NotificationType::NAV_ENTRY_COMMITTED));
1199 EXPECT_TRUE(details.is_in_page);
1200 EXPECT_TRUE(details.did_replace_entry);
1201 EXPECT_EQ(2, controller().entry_count());
1202 }
1203
1204 // Perform a client redirect to a new page.
1205 {
1206 const GURL url("http://foo3/");
1207 ViewHostMsg_FrameNavigate_Params params;
1208 params.page_id = 2; // New page_id
1209 params.url = url;
1210 params.transition = PageTransition::CLIENT_REDIRECT;
1211 params.redirects.push_back(GURL("http://foo2/#a"));
1212 params.redirects.push_back(url);
1213 params.should_update_history = true;
1214 params.gesture = NavigationGestureUnknown;
1215 params.is_post = false;
1216
1217 // This SHOULD generate a new entry.
1218 NavigationController::LoadCommittedDetails details;
1219 EXPECT_TRUE(controller().RendererDidNavigate(params, 0, &details));
1220 EXPECT_TRUE(notifications.Check1AndReset(
1221 NotificationType::NAV_ENTRY_COMMITTED));
1222 EXPECT_FALSE(details.is_in_page);
1223 EXPECT_EQ(3, controller().entry_count());
1224 }
1225
1226 // Verify that BACK brings us back to http://foo2/.
1227 {
1228 const GURL url("http://foo2/");
1229 controller().GoBack();
1230 rvh()->SendNavigate(1, url);
1231 EXPECT_TRUE(notifications.Check1AndReset(
1232 NotificationType::NAV_ENTRY_COMMITTED));
1233 EXPECT_EQ(url, controller().GetActiveEntry()->url());
1234 }
1235 }
1236
1237 // NotificationObserver implementation used in verifying we've received the
1238 // NotificationType::NAV_LIST_PRUNED method.
1239 class PrunedListener : public NotificationObserver {
1240 public:
1241 explicit PrunedListener(NavigationController* controller)
1242 : notification_count_(0) {
1243 registrar_.Add(this, NotificationType::NAV_LIST_PRUNED,
1244 Source<NavigationController>(controller));
1245 }
1246
1247 virtual void Observe(NotificationType type,
1248 const NotificationSource& source,
1249 const NotificationDetails& details) {
1250 if (type == NotificationType::NAV_LIST_PRUNED) {
1251 notification_count_++;
1252 details_ = *(Details<NavigationController::PrunedDetails>(details).ptr());
1253 }
1254 }
1255
1256 // Number of times NAV_LIST_PRUNED has been observed.
1257 int notification_count_;
1258
1259 // Details from the last NAV_LIST_PRUNED.
1260 NavigationController::PrunedDetails details_;
1261
1262 private:
1263 NotificationRegistrar registrar_;
1264
1265 DISALLOW_COPY_AND_ASSIGN(PrunedListener);
1266 };
1267
1268 // Tests that we limit the number of navigation entries created correctly.
1269 TEST_F(NavigationControllerTest, EnforceMaxNavigationCount) {
1270 size_t original_count = NavigationController::max_entry_count();
1271 const int kMaxEntryCount = 5;
1272
1273 NavigationController::set_max_entry_count(kMaxEntryCount);
1274
1275 int url_index;
1276 // Load up to the max count, all entries should be there.
1277 for (url_index = 0; url_index < kMaxEntryCount; url_index++) {
1278 GURL url(StringPrintf("http://www.a.com/%d", url_index));
1279 controller().LoadURL(url, GURL(), PageTransition::TYPED);
1280 rvh()->SendNavigate(url_index, url);
1281 }
1282
1283 EXPECT_EQ(controller().entry_count(), kMaxEntryCount);
1284
1285 // Created a PrunedListener to observe prune notifications.
1286 PrunedListener listener(&controller());
1287
1288 // Navigate some more.
1289 GURL url(StringPrintf("http://www.a.com/%d", url_index));
1290 controller().LoadURL(url, GURL(), PageTransition::TYPED);
1291 rvh()->SendNavigate(url_index, url);
1292 url_index++;
1293
1294 // We should have got a pruned navigation.
1295 EXPECT_EQ(1, listener.notification_count_);
1296 EXPECT_TRUE(listener.details_.from_front);
1297 EXPECT_EQ(1, listener.details_.count);
1298
1299 // We expect http://www.a.com/0 to be gone.
1300 EXPECT_EQ(controller().entry_count(), kMaxEntryCount);
1301 EXPECT_EQ(controller().GetEntryAtIndex(0)->url(),
1302 GURL("http:////www.a.com/1"));
1303
1304 // More navigations.
1305 for (int i = 0; i < 3; i++) {
1306 url = GURL(StringPrintf("http:////www.a.com/%d", url_index));
1307 controller().LoadURL(url, GURL(), PageTransition::TYPED);
1308 rvh()->SendNavigate(url_index, url);
1309 url_index++;
1310 }
1311 EXPECT_EQ(controller().entry_count(), kMaxEntryCount);
1312 EXPECT_EQ(controller().GetEntryAtIndex(0)->url(),
1313 GURL("http:////www.a.com/4"));
1314
1315 NavigationController::set_max_entry_count(original_count);
1316 }
1317
1318 // Tests that we can do a restore and navigate to the restored entries and
1319 // everything is updated properly. This can be tricky since there is no
1320 // SiteInstance for the entries created initially.
1321 TEST_F(NavigationControllerTest, RestoreNavigate) {
1322 // Create a NavigationController with a restored set of tabs.
1323 GURL url("http://foo");
1324 std::vector<TabNavigation> navigations;
1325 navigations.push_back(TabNavigation(0, url, GURL(),
1326 ASCIIToUTF16("Title"), "state",
1327 PageTransition::LINK));
1328 TabContents our_contents(profile(), NULL, MSG_ROUTING_NONE, NULL, NULL);
1329 NavigationController& our_controller = our_contents.controller();
1330 our_controller.RestoreFromState(navigations, 0, true);
1331 our_controller.GoToIndex(0);
1332
1333 // We should now have one entry, and it should be "pending".
1334 EXPECT_EQ(1, our_controller.entry_count());
1335 EXPECT_EQ(our_controller.GetEntryAtIndex(0),
1336 our_controller.pending_entry());
1337 EXPECT_EQ(0, our_controller.GetEntryAtIndex(0)->page_id());
1338 EXPECT_EQ(NavigationEntry::RESTORE_LAST_SESSION,
1339 our_controller.GetEntryAtIndex(0)->restore_type());
1340
1341 // Say we navigated to that entry.
1342 ViewHostMsg_FrameNavigate_Params params;
1343 params.page_id = 0;
1344 params.url = url;
1345 params.transition = PageTransition::LINK;
1346 params.should_update_history = false;
1347 params.gesture = NavigationGestureUser;
1348 params.is_post = false;
1349 NavigationController::LoadCommittedDetails details;
1350 our_controller.RendererDidNavigate(params, 0, &details);
1351
1352 // There should be no longer any pending entry and one committed one. This
1353 // means that we were able to locate the entry, assign its site instance, and
1354 // commit it properly.
1355 EXPECT_EQ(1, our_controller.entry_count());
1356 EXPECT_EQ(0, our_controller.last_committed_entry_index());
1357 EXPECT_FALSE(our_controller.pending_entry());
1358 EXPECT_EQ(url,
1359 our_controller.GetLastCommittedEntry()->site_instance()->site());
1360 EXPECT_EQ(NavigationEntry::RESTORE_NONE,
1361 our_controller.GetEntryAtIndex(0)->restore_type());
1362 }
1363
1364 // Make sure that the page type and stuff is correct after an interstitial.
1365 TEST_F(NavigationControllerTest, Interstitial) {
1366 // First navigate somewhere normal.
1367 const GURL url1("http://foo");
1368 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
1369 rvh()->SendNavigate(0, url1);
1370
1371 // Now navigate somewhere with an interstitial.
1372 const GURL url2("http://bar");
1373 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
1374 controller().pending_entry()->set_page_type(INTERSTITIAL_PAGE);
1375
1376 // At this point the interstitial will be displayed and the load will still
1377 // be pending. If the user continues, the load will commit.
1378 rvh()->SendNavigate(1, url2);
1379
1380 // The page should be a normal page again.
1381 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->url());
1382 EXPECT_EQ(NORMAL_PAGE, controller().GetLastCommittedEntry()->page_type());
1383 }
1384
1385 TEST_F(NavigationControllerTest, RemoveEntry) {
1386 const GURL url1("http://foo1");
1387 const GURL url2("http://foo2");
1388 const GURL url3("http://foo3");
1389 const GURL url4("http://foo4");
1390 const GURL url5("http://foo5");
1391 const GURL pending_url("http://pending");
1392 const GURL default_url("http://default");
1393
1394 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
1395 rvh()->SendNavigate(0, url1);
1396 controller().LoadURL(url2, GURL(), PageTransition::TYPED);
1397 rvh()->SendNavigate(1, url2);
1398 controller().LoadURL(url3, GURL(), PageTransition::TYPED);
1399 rvh()->SendNavigate(2, url3);
1400 controller().LoadURL(url4, GURL(), PageTransition::TYPED);
1401 rvh()->SendNavigate(3, url4);
1402 controller().LoadURL(url5, GURL(), PageTransition::TYPED);
1403 rvh()->SendNavigate(4, url5);
1404
1405 // Remove the last entry.
1406 controller().RemoveEntryAtIndex(
1407 controller().entry_count() - 1, default_url);
1408 EXPECT_EQ(4, controller().entry_count());
1409 EXPECT_EQ(3, controller().last_committed_entry_index());
1410 NavigationEntry* pending_entry = controller().pending_entry();
1411 EXPECT_TRUE(pending_entry && pending_entry->url() == url4);
1412
1413 // Add a pending entry.
1414 controller().LoadURL(pending_url, GURL(), PageTransition::TYPED);
1415 // Now remove the last entry.
1416 controller().RemoveEntryAtIndex(
1417 controller().entry_count() - 1, default_url);
1418 // The pending entry should have been discarded and the last committed entry
1419 // removed.
1420 EXPECT_EQ(3, controller().entry_count());
1421 EXPECT_EQ(2, controller().last_committed_entry_index());
1422 pending_entry = controller().pending_entry();
1423 EXPECT_TRUE(pending_entry && pending_entry->url() == url3);
1424
1425 // Remove an entry which is not the last committed one.
1426 controller().RemoveEntryAtIndex(0, default_url);
1427 EXPECT_EQ(2, controller().entry_count());
1428 EXPECT_EQ(1, controller().last_committed_entry_index());
1429 // No navigation should have been initiated since we did not remove the
1430 // current entry.
1431 EXPECT_FALSE(controller().pending_entry());
1432
1433 // Remove the 2 remaining entries.
1434 controller().RemoveEntryAtIndex(1, default_url);
1435 controller().RemoveEntryAtIndex(0, default_url);
1436
1437 // This should have created a pending default entry.
1438 EXPECT_EQ(0, controller().entry_count());
1439 EXPECT_EQ(-1, controller().last_committed_entry_index());
1440 pending_entry = controller().pending_entry();
1441 EXPECT_TRUE(pending_entry && pending_entry->url() == default_url);
1442 }
1443
1444 // Tests the transient entry, making sure it goes away with all navigations.
1445 TEST_F(NavigationControllerTest, TransientEntry) {
1446 TestNotificationTracker notifications;
1447 RegisterForAllNavNotifications(&notifications, &controller());
1448
1449 const GURL url0("http://foo0");
1450 const GURL url1("http://foo1");
1451 const GURL url2("http://foo2");
1452 const GURL url3("http://foo3");
1453 const GURL url4("http://foo4");
1454 const GURL transient_url("http://transient");
1455
1456 controller().LoadURL(url0, GURL(), PageTransition::TYPED);
1457 rvh()->SendNavigate(0, url0);
1458 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
1459 rvh()->SendNavigate(1, url1);
1460
1461 notifications.Reset();
1462
1463 // Adding a transient with no pending entry.
1464 NavigationEntry* transient_entry = new NavigationEntry;
1465 transient_entry->set_url(transient_url);
1466 controller().AddTransientEntry(transient_entry);
1467
1468 // We should not have received any notifications.
1469 EXPECT_EQ(0U, notifications.size());
1470
1471 // Check our state.
1472 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url());
1473 EXPECT_EQ(controller().entry_count(), 3);
1474 EXPECT_EQ(controller().last_committed_entry_index(), 1);
1475 EXPECT_EQ(controller().pending_entry_index(), -1);
1476 EXPECT_TRUE(controller().GetLastCommittedEntry());
1477 EXPECT_FALSE(controller().pending_entry());
1478 EXPECT_TRUE(controller().CanGoBack());
1479 EXPECT_FALSE(controller().CanGoForward());
1480 EXPECT_EQ(contents()->GetMaxPageID(), 1);
1481
1482 // Navigate.
1483 controller().LoadURL(url2, GURL(), PageTransition::TYPED);
1484 rvh()->SendNavigate(2, url2);
1485
1486 // We should have navigated, transient entry should be gone.
1487 EXPECT_EQ(url2, controller().GetActiveEntry()->url());
1488 EXPECT_EQ(controller().entry_count(), 3);
1489
1490 // Add a transient again, then navigate with no pending entry this time.
1491 transient_entry = new NavigationEntry;
1492 transient_entry->set_url(transient_url);
1493 controller().AddTransientEntry(transient_entry);
1494 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url());
1495 rvh()->SendNavigate(3, url3);
1496 // Transient entry should be gone.
1497 EXPECT_EQ(url3, controller().GetActiveEntry()->url());
1498 EXPECT_EQ(controller().entry_count(), 4);
1499
1500 // Initiate a navigation, add a transient then commit navigation.
1501 controller().LoadURL(url4, GURL(), PageTransition::TYPED);
1502 transient_entry = new NavigationEntry;
1503 transient_entry->set_url(transient_url);
1504 controller().AddTransientEntry(transient_entry);
1505 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url());
1506 rvh()->SendNavigate(4, url4);
1507 EXPECT_EQ(url4, controller().GetActiveEntry()->url());
1508 EXPECT_EQ(controller().entry_count(), 5);
1509
1510 // Add a transient and go back. This should simply remove the transient.
1511 transient_entry = new NavigationEntry;
1512 transient_entry->set_url(transient_url);
1513 controller().AddTransientEntry(transient_entry);
1514 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url());
1515 EXPECT_TRUE(controller().CanGoBack());
1516 EXPECT_FALSE(controller().CanGoForward());
1517 controller().GoBack();
1518 // Transient entry should be gone.
1519 EXPECT_EQ(url4, controller().GetActiveEntry()->url());
1520 EXPECT_EQ(controller().entry_count(), 5);
1521 rvh()->SendNavigate(3, url3);
1522
1523 // Add a transient and go to an entry before the current one.
1524 transient_entry = new NavigationEntry;
1525 transient_entry->set_url(transient_url);
1526 controller().AddTransientEntry(transient_entry);
1527 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url());
1528 controller().GoToIndex(1);
1529 // The navigation should have been initiated, transient entry should be gone.
1530 EXPECT_EQ(url1, controller().GetActiveEntry()->url());
1531 rvh()->SendNavigate(1, url1);
1532
1533 // Add a transient and go to an entry after the current one.
1534 transient_entry = new NavigationEntry;
1535 transient_entry->set_url(transient_url);
1536 controller().AddTransientEntry(transient_entry);
1537 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url());
1538 controller().GoToIndex(3);
1539 // The navigation should have been initiated, transient entry should be gone.
1540 // Because of the transient entry that is removed, going to index 3 makes us
1541 // land on url2.
1542 EXPECT_EQ(url2, controller().GetActiveEntry()->url());
1543 rvh()->SendNavigate(2, url2);
1544
1545 // Add a transient and go forward.
1546 transient_entry = new NavigationEntry;
1547 transient_entry->set_url(transient_url);
1548 controller().AddTransientEntry(transient_entry);
1549 EXPECT_EQ(transient_url, controller().GetActiveEntry()->url());
1550 EXPECT_TRUE(controller().CanGoForward());
1551 controller().GoForward();
1552 // We should have navigated, transient entry should be gone.
1553 EXPECT_EQ(url3, controller().GetActiveEntry()->url());
1554 rvh()->SendNavigate(3, url3);
1555
1556 // Ensure the URLS are correct.
1557 EXPECT_EQ(controller().entry_count(), 5);
1558 EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), url0);
1559 EXPECT_EQ(controller().GetEntryAtIndex(1)->url(), url1);
1560 EXPECT_EQ(controller().GetEntryAtIndex(2)->url(), url2);
1561 EXPECT_EQ(controller().GetEntryAtIndex(3)->url(), url3);
1562 EXPECT_EQ(controller().GetEntryAtIndex(4)->url(), url4);
1563 }
1564
1565 // Tests that IsInPageNavigation returns appropriate results. Prevents
1566 // regression for bug 1126349.
1567 TEST_F(NavigationControllerTest, IsInPageNavigation) {
1568 // Navigate to URL with no refs.
1569 const GURL url("http://www.google.com/home.html");
1570 rvh()->SendNavigate(0, url);
1571
1572 // Reloading the page is not an in-page navigation.
1573 EXPECT_FALSE(controller().IsURLInPageNavigation(url));
1574 const GURL other_url("http://www.google.com/add.html");
1575 EXPECT_FALSE(controller().IsURLInPageNavigation(other_url));
1576 const GURL url_with_ref("http://www.google.com/home.html#my_ref");
1577 EXPECT_TRUE(controller().IsURLInPageNavigation(url_with_ref));
1578
1579 // Navigate to URL with refs.
1580 rvh()->SendNavigate(1, url_with_ref);
1581
1582 // Reloading the page is not an in-page navigation.
1583 EXPECT_FALSE(controller().IsURLInPageNavigation(url_with_ref));
1584 EXPECT_FALSE(controller().IsURLInPageNavigation(url));
1585 EXPECT_FALSE(controller().IsURLInPageNavigation(other_url));
1586 const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref");
1587 EXPECT_TRUE(controller().IsURLInPageNavigation(
1588 other_url_with_ref));
1589 }
1590
1591 // Some pages can have subframes with the same base URL (minus the reference) as
1592 // the main page. Even though this is hard, it can happen, and we don't want
1593 // these subframe navigations to affect the toplevel document. They should
1594 // instead be ignored. http://crbug.com/5585
1595 TEST_F(NavigationControllerTest, SameSubframe) {
1596 // Navigate the main frame.
1597 const GURL url("http://www.google.com/");
1598 rvh()->SendNavigate(0, url);
1599
1600 // We should be at the first navigation entry.
1601 EXPECT_EQ(controller().entry_count(), 1);
1602 EXPECT_EQ(controller().last_committed_entry_index(), 0);
1603
1604 // Navigate a subframe that would normally count as in-page.
1605 const GURL subframe("http://www.google.com/#");
1606 ViewHostMsg_FrameNavigate_Params params;
1607 params.page_id = 0;
1608 params.url = subframe;
1609 params.transition = PageTransition::AUTO_SUBFRAME;
1610 params.should_update_history = false;
1611 params.gesture = NavigationGestureAuto;
1612 params.is_post = false;
1613 NavigationController::LoadCommittedDetails details;
1614 EXPECT_FALSE(controller().RendererDidNavigate(params, 0, &details));
1615
1616 // Nothing should have changed.
1617 EXPECT_EQ(controller().entry_count(), 1);
1618 EXPECT_EQ(controller().last_committed_entry_index(), 0);
1619 }
1620
1621 // Test view source redirection is reflected in title bar.
1622 TEST_F(NavigationControllerTest, ViewSourceRedirect) {
1623 const char kUrl[] = "view-source:http://redirect.to/google.com";
1624 const char kResult[] = "http://google.com";
1625 const char kExpected[] = "view-source:google.com";
1626 const GURL url(kUrl);
1627 const GURL result_url(kResult);
1628
1629 controller().LoadURL(url, GURL(), PageTransition::TYPED);
1630
1631 ViewHostMsg_FrameNavigate_Params params;
1632 params.page_id = 0;
1633 params.url = result_url;
1634 params.transition = PageTransition::SERVER_REDIRECT;
1635 params.should_update_history = false;
1636 params.gesture = NavigationGestureAuto;
1637 params.is_post = false;
1638 NavigationController::LoadCommittedDetails details;
1639 controller().RendererDidNavigate(params, 0, &details);
1640
1641 EXPECT_EQ(ASCIIToUTF16(kExpected), contents()->GetTitle());
1642 EXPECT_TRUE(contents()->ShouldDisplayURL());
1643 }
1644
1645 // Make sure that on cloning a tabcontents and going back needs_reload is false.
1646 TEST_F(NavigationControllerTest, CloneAndGoBack) {
1647 const GURL url1("http://foo1");
1648 const GURL url2("http://foo2");
1649
1650 NavigateAndCommit(url1);
1651 NavigateAndCommit(url2);
1652
1653 scoped_ptr<TabContents> clone(controller().tab_contents()->Clone());
1654
1655 ASSERT_EQ(2, clone->controller().entry_count());
1656 EXPECT_TRUE(clone->controller().needs_reload());
1657 clone->controller().GoBack();
1658 // Navigating back should have triggered needs_reload_ to go false.
1659 EXPECT_FALSE(clone->controller().needs_reload());
1660 }
1661
1662 // Make sure that cloning a tabcontents doesn't copy interstitials.
1663 TEST_F(NavigationControllerTest, CloneOmitsInterstitials) {
1664 const GURL url1("http://foo1");
1665 const GURL url2("http://foo2");
1666
1667 NavigateAndCommit(url1);
1668 NavigateAndCommit(url2);
1669
1670 // Add an interstitial entry. Should be deleted with controller.
1671 NavigationEntry* interstitial_entry = new NavigationEntry();
1672 interstitial_entry->set_page_type(INTERSTITIAL_PAGE);
1673 controller().AddTransientEntry(interstitial_entry);
1674
1675 scoped_ptr<TabContents> clone(controller().tab_contents()->Clone());
1676
1677 ASSERT_EQ(2, clone->controller().entry_count());
1678 }
1679
1680 // Tests a subframe navigation while a toplevel navigation is pending.
1681 // http://crbug.com/43967
1682 TEST_F(NavigationControllerTest, SubframeWhilePending) {
1683 // Load the first page.
1684 const GURL url1("http://foo/");
1685 NavigateAndCommit(url1);
1686
1687 // Now start a pending load to a totally different page, but don't commit it.
1688 const GURL url2("http://bar/");
1689 controller().LoadURL(url2, GURL(), PageTransition::TYPED);
1690
1691 // Send a subframe update from the first page, as if one had just
1692 // automatically loaded. Auto subframes don't increment the page ID.
1693 const GURL url1_sub("http://foo/subframe");
1694 ViewHostMsg_FrameNavigate_Params params;
1695 params.page_id = controller().GetLastCommittedEntry()->page_id();
1696 params.url = url1_sub;
1697 params.transition = PageTransition::AUTO_SUBFRAME;
1698 params.should_update_history = false;
1699 params.gesture = NavigationGestureAuto;
1700 params.is_post = false;
1701 NavigationController::LoadCommittedDetails details;
1702
1703 // This should return false meaning that nothing was actually updated.
1704 EXPECT_FALSE(controller().RendererDidNavigate(params, 0, &details));
1705
1706 // The notification should have updated the last committed one, and not
1707 // the pending load.
1708 EXPECT_EQ(url1, controller().GetLastCommittedEntry()->url());
1709
1710 // The active entry should be unchanged by the subframe load.
1711 EXPECT_EQ(url2, controller().GetActiveEntry()->url());
1712 }
1713
1714 // Tests CopyStateFromAndPrune with 2 urls in source, 1 in dest.
1715 TEST_F(NavigationControllerTest, CopyStateFromAndPrune) {
1716 SessionID id(controller().session_id());
1717 const GURL url1("http://foo1");
1718 const GURL url2("http://foo2");
1719 const GURL url3("http://foo3");
1720
1721 NavigateAndCommit(url1);
1722 NavigateAndCommit(url2);
1723
1724 scoped_ptr<TestTabContents> other_contents(CreateTestTabContents());
1725 NavigationController& other_controller = other_contents->controller();
1726 SessionID other_id(other_controller.session_id());
1727 other_contents->NavigateAndCommit(url3);
1728 other_controller.CopyStateFromAndPrune(&controller());
1729
1730 // other_controller should now contain the 3 urls: url1, url2 and url3.
1731
1732 ASSERT_EQ(3, other_controller.entry_count());
1733
1734 ASSERT_EQ(2, other_controller.GetCurrentEntryIndex());
1735
1736 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url());
1737 EXPECT_EQ(url2, other_controller.GetEntryAtIndex(1)->url());
1738 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(2)->url());
1739
1740 // Make sure session ids didn't change.
1741 EXPECT_EQ(id.id(), controller().session_id().id());
1742 EXPECT_EQ(other_id.id(), other_controller.session_id().id());
1743 }
1744
1745 // Test CopyStateFromAndPrune with 2 urls, the first selected and nothing in
1746 // the target.
1747 TEST_F(NavigationControllerTest, CopyStateFromAndPrune2) {
1748 SessionID id(controller().session_id());
1749 const GURL url1("http://foo1");
1750 const GURL url2("http://foo2");
1751 const GURL url3("http://foo3");
1752
1753 NavigateAndCommit(url1);
1754 NavigateAndCommit(url2);
1755 controller().GoBack();
1756
1757 scoped_ptr<TestTabContents> other_contents(CreateTestTabContents());
1758 NavigationController& other_controller = other_contents->controller();
1759 SessionID other_id(other_controller.session_id());
1760 other_controller.CopyStateFromAndPrune(&controller());
1761
1762 // other_controller should now contain the 1 url: url1.
1763
1764 ASSERT_EQ(1, other_controller.entry_count());
1765
1766 ASSERT_EQ(0, other_controller.GetCurrentEntryIndex());
1767
1768 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url());
1769
1770 // Make sure session ids didn't change.
1771 EXPECT_EQ(id.id(), controller().session_id().id());
1772 EXPECT_EQ(other_id.id(), other_controller.session_id().id());
1773 }
1774
1775 // Test CopyStateFromAndPrune with 2 urls, the first selected and nothing in
1776 // the target.
1777 TEST_F(NavigationControllerTest, CopyStateFromAndPrune3) {
1778 SessionID id(controller().session_id());
1779 const GURL url1("http://foo1");
1780 const GURL url2("http://foo2");
1781 const GURL url3("http://foo3");
1782
1783 NavigateAndCommit(url1);
1784 NavigateAndCommit(url2);
1785 controller().GoBack();
1786
1787 scoped_ptr<TestTabContents> other_contents(CreateTestTabContents());
1788 NavigationController& other_controller = other_contents->controller();
1789 SessionID other_id(other_controller.session_id());
1790 other_controller.LoadURL(url3, GURL(), PageTransition::TYPED);
1791 other_controller.CopyStateFromAndPrune(&controller());
1792
1793 // other_controller should now contain 1 entry for url1, and a pending entry
1794 // for url3.
1795
1796 ASSERT_EQ(1, other_controller.entry_count());
1797
1798 EXPECT_EQ(0, other_controller.GetCurrentEntryIndex());
1799
1800 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url());
1801
1802 // And there should be a pending entry for url3.
1803 ASSERT_TRUE(other_controller.pending_entry());
1804
1805 EXPECT_EQ(url3, other_controller.pending_entry()->url());
1806
1807 // Make sure session ids didn't change.
1808 EXPECT_EQ(id.id(), controller().session_id().id());
1809 EXPECT_EQ(other_id.id(), other_controller.session_id().id());
1810 }
1811
1812 // Tests that navigations initiated from the page (with the history object)
1813 // work as expected without navigation entries.
1814 TEST_F(NavigationControllerTest, HistoryNavigate) {
1815 const GURL url1("http://foo1");
1816 const GURL url2("http://foo2");
1817 const GURL url3("http://foo3");
1818
1819 NavigateAndCommit(url1);
1820 NavigateAndCommit(url2);
1821 NavigateAndCommit(url3);
1822 controller().GoBack();
1823 contents()->CommitPendingNavigation();
1824
1825 // Simulate the page calling history.back(), it should not create a pending
1826 // entry.
1827 contents()->OnGoToEntryAtOffset(-1);
1828 EXPECT_EQ(-1, controller().pending_entry_index());
1829 // The actual cross-navigation is suspended until the current RVH tells us
1830 // it unloaded, simulate that.
1831 contents()->ProceedWithCrossSiteNavigation();
1832 // Also make sure we told the page to navigate.
1833 const IPC::Message* message =
1834 process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
1835 ASSERT_TRUE(message != NULL);
1836 Tuple1<ViewMsg_Navigate_Params> nav_params;
1837 ViewMsg_Navigate::Read(message, &nav_params);
1838 EXPECT_EQ(url1, nav_params.a.url);
1839 process()->sink().ClearMessages();
1840
1841 // Now test history.forward()
1842 contents()->OnGoToEntryAtOffset(1);
1843 EXPECT_EQ(-1, controller().pending_entry_index());
1844 // The actual cross-navigation is suspended until the current RVH tells us
1845 // it unloaded, simulate that.
1846 contents()->ProceedWithCrossSiteNavigation();
1847 message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
1848 ASSERT_TRUE(message != NULL);
1849 ViewMsg_Navigate::Read(message, &nav_params);
1850 EXPECT_EQ(url3, nav_params.a.url);
1851 process()->sink().ClearMessages();
1852
1853 // Make sure an extravagant history.go() doesn't break.
1854 contents()->OnGoToEntryAtOffset(120); // Out of bounds.
1855 EXPECT_EQ(-1, controller().pending_entry_index());
1856 message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
1857 EXPECT_TRUE(message == NULL);
1858 }
1859
1860 // Test call to PruneAllButActive for the only entry.
1861 TEST_F(NavigationControllerTest, PruneAllButActiveForSingle) {
1862 const GURL url1("http://foo1");
1863 NavigateAndCommit(url1);
1864 controller().PruneAllButActive();
1865
1866 EXPECT_EQ(-1, controller().pending_entry_index());
1867 EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), url1);
1868 }
1869
1870 // Test call to PruneAllButActive for last entry.
1871 TEST_F(NavigationControllerTest, PruneAllButActiveForLast) {
1872 const GURL url1("http://foo1");
1873 const GURL url2("http://foo2");
1874 const GURL url3("http://foo3");
1875
1876 NavigateAndCommit(url1);
1877 NavigateAndCommit(url2);
1878 NavigateAndCommit(url3);
1879 controller().GoBack();
1880 controller().GoBack();
1881 contents()->CommitPendingNavigation();
1882
1883 controller().PruneAllButActive();
1884
1885 EXPECT_EQ(-1, controller().pending_entry_index());
1886 EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), url1);
1887 }
1888
1889 // Test call to PruneAllButActive for intermediate entry.
1890 TEST_F(NavigationControllerTest, PruneAllButActiveForIntermediate) {
1891 const GURL url1("http://foo1");
1892 const GURL url2("http://foo2");
1893 const GURL url3("http://foo3");
1894
1895 NavigateAndCommit(url1);
1896 NavigateAndCommit(url2);
1897 NavigateAndCommit(url3);
1898 controller().GoBack();
1899 contents()->CommitPendingNavigation();
1900
1901 controller().PruneAllButActive();
1902
1903 EXPECT_EQ(-1, controller().pending_entry_index());
1904 EXPECT_EQ(controller().GetEntryAtIndex(0)->url(), url2);
1905 }
1906
1907 // Test call to PruneAllButActive for intermediate entry.
1908 TEST_F(NavigationControllerTest, PruneAllButActiveForPending) {
1909 const GURL url1("http://foo1");
1910 const GURL url2("http://foo2");
1911 const GURL url3("http://foo3");
1912
1913 NavigateAndCommit(url1);
1914 NavigateAndCommit(url2);
1915 NavigateAndCommit(url3);
1916 controller().GoBack();
1917
1918 controller().PruneAllButActive();
1919
1920 EXPECT_EQ(0, controller().pending_entry_index());
1921 }
1922
1923 // Test call to PruneAllButActive for transient entry.
1924 TEST_F(NavigationControllerTest, PruneAllButActiveForTransient) {
1925 const GURL url0("http://foo0");
1926 const GURL url1("http://foo1");
1927 const GURL transient_url("http://transient");
1928
1929 controller().LoadURL(url0, GURL(), PageTransition::TYPED);
1930 rvh()->SendNavigate(0, url0);
1931 controller().LoadURL(url1, GURL(), PageTransition::TYPED);
1932 rvh()->SendNavigate(1, url1);
1933
1934 // Adding a transient with no pending entry.
1935 NavigationEntry* transient_entry = new NavigationEntry;
1936 transient_entry->set_url(transient_url);
1937 controller().AddTransientEntry(transient_entry);
1938
1939 controller().PruneAllButActive();
1940
1941 EXPECT_EQ(-1, controller().pending_entry_index());
1942 EXPECT_EQ(-1, controller().pending_entry_index());
1943 EXPECT_EQ(controller().GetTransientEntry()->url(), transient_url);
1944 }
1945
1946 /* TODO(brettw) These test pass on my local machine but fail on the XP buildbot
1947 (but not Vista) cleaning up the directory after they run.
1948 This should be fixed.
1949
1950 // A basic test case. Navigates to a single url, and make sure the history
1951 // db matches.
1952 TEST_F(NavigationControllerHistoryTest, Basic) {
1953 controller().LoadURL(url0, GURL(), PageTransition::LINK);
1954 rvh()->SendNavigate(0, url0);
1955
1956 GetLastSession();
1957
1958 session_helper_.AssertSingleWindowWithSingleTab(windows_, 1);
1959 session_helper_.AssertTabEquals(0, 0, 1, *(windows_[0]->tabs[0]));
1960 TabNavigation nav1(0, url0, GURL(), string16(),
1961 webkit_glue::CreateHistoryStateForURL(url0),
1962 PageTransition::LINK);
1963 session_helper_.AssertNavigationEquals(nav1,
1964 windows_[0]->tabs[0]->navigations[0]);
1965 }
1966
1967 // Navigates to three urls, then goes back and make sure the history database
1968 // is in sync.
1969 TEST_F(NavigationControllerHistoryTest, NavigationThenBack) {
1970 rvh()->SendNavigate(0, url0);
1971 rvh()->SendNavigate(1, url1);
1972 rvh()->SendNavigate(2, url2);
1973
1974 controller().GoBack();
1975 rvh()->SendNavigate(1, url1);
1976
1977 GetLastSession();
1978
1979 session_helper_.AssertSingleWindowWithSingleTab(windows_, 3);
1980 session_helper_.AssertTabEquals(0, 1, 3, *(windows_[0]->tabs[0]));
1981
1982 TabNavigation nav(0, url0, GURL(), string16(),
1983 webkit_glue::CreateHistoryStateForURL(url0),
1984 PageTransition::LINK);
1985 session_helper_.AssertNavigationEquals(nav,
1986 windows_[0]->tabs[0]->navigations[0]);
1987 nav.set_url(url1);
1988 session_helper_.AssertNavigationEquals(nav,
1989 windows_[0]->tabs[0]->navigations[1]);
1990 nav.set_url(url2);
1991 session_helper_.AssertNavigationEquals(nav,
1992 windows_[0]->tabs[0]->navigations[2]);
1993 }
1994
1995 // Navigates to three urls, then goes back twice, then loads a new url.
1996 TEST_F(NavigationControllerHistoryTest, NavigationPruning) {
1997 rvh()->SendNavigate(0, url0);
1998 rvh()->SendNavigate(1, url1);
1999 rvh()->SendNavigate(2, url2);
2000
2001 controller().GoBack();
2002 rvh()->SendNavigate(1, url1);
2003
2004 controller().GoBack();
2005 rvh()->SendNavigate(0, url0);
2006
2007 rvh()->SendNavigate(3, url2);
2008
2009 // Now have url0, and url2.
2010
2011 GetLastSession();
2012
2013 session_helper_.AssertSingleWindowWithSingleTab(windows_, 2);
2014 session_helper_.AssertTabEquals(0, 1, 2, *(windows_[0]->tabs[0]));
2015
2016 TabNavigation nav(0, url0, GURL(), string16(),
2017 webkit_glue::CreateHistoryStateForURL(url0),
2018 PageTransition::LINK);
2019 session_helper_.AssertNavigationEquals(nav,
2020 windows_[0]->tabs[0]->navigations[0]);
2021 nav.set_url(url2);
2022 session_helper_.AssertNavigationEquals(nav,
2023 windows_[0]->tabs[0]->navigations[1]);
2024 }
2025 */
OLDNEW
« no previous file with comments | « chrome/browser/tab_contents/navigation_controller.cc ('k') | chrome/browser/tab_contents/navigation_entry.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698