1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/search/instant_page.h" 6 7 #include "base/command_line.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "chrome/browser/ui/search/search_tab_helper.h" 10 #include "chrome/common/chrome_switches.h" 11 #include "chrome/common/render_messages.h" 12 #include "chrome/common/url_constants.h" 13 #include "chrome/test/base/chrome_render_view_host_test_harness.h" 14 #include "content/public/browser/navigation_controller.h" 15 #include "content/public/browser/navigation_entry.h" 16 #include "content/public/browser/web_contents.h" 17 #include "content/public/test/mock_render_process_host.h" 18 #include "ipc/ipc_test_sink.h" 19 #include "testing/gmock/include/gmock/gmock.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 #include "url/gurl.h" 22 23 class Profile; 24 25 namespace { 26 27 class FakePageDelegate : public InstantPage::Delegate { 28 public: 29 virtual ~FakePageDelegate() { 30 } 31 32 MOCK_METHOD2(InstantSupportDetermined, 33 void(const content::WebContents* contents, 34 bool supports_instant)); 35 MOCK_METHOD1(InstantPageRenderProcessGone, 36 void(const content::WebContents* contents)); 37 MOCK_METHOD2(InstantPageAboutToNavigateMainFrame, 38 void(const content::WebContents* contents, 39 const GURL& url)); 40 MOCK_METHOD5(NavigateToURL, 41 void(const content::WebContents* contents, 42 const GURL& url, 43 content::PageTransition transition, 44 WindowOpenDisposition disposition, 45 bool is_search_type)); 46 }; 47 48 } // namespace 49 50 class InstantPageTest : public ChromeRenderViewHostTestHarness { 51 public: 52 virtual void SetUp() OVERRIDE; 53 54 bool MessageWasSent(uint32 id) { 55 return process()->sink().GetFirstMessageMatching(id) != NULL; 56 } 57 58 scoped_ptr<InstantPage> page; 59 FakePageDelegate delegate; 60 }; 61 62 void InstantPageTest::SetUp() { 63 ChromeRenderViewHostTestHarness::SetUp(); 64 SearchTabHelper::CreateForWebContents(web_contents()); 65 } 66 67 TEST_F(InstantPageTest, IsLocal) { 68 page.reset(new InstantPage(&delegate, "", NULL, false)); 69 EXPECT_FALSE(page->supports_instant()); 70 EXPECT_FALSE(page->IsLocal()); 71 page->SetContents(web_contents()); 72 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl)); 73 EXPECT_TRUE(page->IsLocal()); 74 NavigateAndCommit(GURL("http://example.com")); 75 EXPECT_FALSE(page->IsLocal()); 76 } 77 78 TEST_F(InstantPageTest, DetermineIfPageSupportsInstant_Local) { 79 page.reset(new InstantPage(&delegate, "", NULL, false)); 80 EXPECT_FALSE(page->supports_instant()); 81 page->SetContents(web_contents()); 82 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl)); 83 EXPECT_TRUE(page->IsLocal()); 84 EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), true)) 85 .Times(1); 86 SearchTabHelper::FromWebContents(web_contents())-> 87 DetermineIfPageSupportsInstant(); 88 EXPECT_TRUE(page->supports_instant()); 89 } 90 91 TEST_F(InstantPageTest, DetermineIfPageSupportsInstant_NonLocal) { 92 page.reset(new InstantPage(&delegate, "", NULL, false)); 93 EXPECT_FALSE(page->supports_instant()); 94 page->SetContents(web_contents()); 95 NavigateAndCommit(GURL("chrome-search://foo/bar")); 96 EXPECT_FALSE(page->IsLocal()); 97 process()->sink().ClearMessages(); 98 SearchTabHelper::FromWebContents(web_contents())-> 99 DetermineIfPageSupportsInstant(); 100 const IPC::Message* message = process()->sink().GetFirstMessageMatching( 101 ChromeViewMsg_DetermineIfPageSupportsInstant::ID); 102 ASSERT_TRUE(message != NULL); 103 EXPECT_EQ(web_contents()->GetRoutingID(), message->routing_id()); 104 } 105 106 TEST_F(InstantPageTest, PageURLDoesntBelongToInstantRenderer) { 107 page.reset(new InstantPage(&delegate, "", NULL, false)); 108 EXPECT_FALSE(page->supports_instant()); 109 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl)); 110 page->SetContents(web_contents()); 111 112 // Navigate to a page URL that doesn't belong to Instant renderer. 113 // SearchTabHelper::DeterminerIfPageSupportsInstant() should return 114 // immediately without dispatching any message to the renderer. 115 NavigateAndCommit(GURL("http://www.example.com")); 116 EXPECT_FALSE(page->IsLocal()); 117 process()->sink().ClearMessages(); 118 EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), false)) 119 .Times(1); 120 121 SearchTabHelper::FromWebContents(web_contents())-> 122 DetermineIfPageSupportsInstant(); 123 const IPC::Message* message = process()->sink().GetFirstMessageMatching( 124 ChromeViewMsg_DetermineIfPageSupportsInstant::ID); 125 ASSERT_TRUE(message == NULL); 126 EXPECT_FALSE(page->supports_instant()); 127 } 128 129 // Test to verify that ChromeViewMsg_DetermineIfPageSupportsInstant message 130 // reply handler updates the instant support state in InstantPage. 131 TEST_F(InstantPageTest, PageSupportsInstant) { 132 page.reset(new InstantPage(&delegate, "", NULL, false)); 133 EXPECT_FALSE(page->supports_instant()); 134 page->SetContents(web_contents()); 135 NavigateAndCommit(GURL("chrome-search://foo/bar")); 136 process()->sink().ClearMessages(); 137 SearchTabHelper::FromWebContents(web_contents())-> 138 DetermineIfPageSupportsInstant(); 139 const IPC::Message* message = process()->sink().GetFirstMessageMatching( 140 ChromeViewMsg_DetermineIfPageSupportsInstant::ID); 141 ASSERT_TRUE(message != NULL); 142 EXPECT_EQ(web_contents()->GetRoutingID(), message->routing_id()); 143 144 EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), true)) 145 .Times(1); 146 147 // Assume the page supports instant. Invoke the message reply handler to make 148 // sure the InstantPage is notified about the instant support state. 149 const content::NavigationEntry* entry = 150 web_contents()->GetController().GetLastCommittedEntry(); 151 EXPECT_TRUE(entry); 152 SearchTabHelper::FromWebContents(web_contents())->InstantSupportChanged(true); 153 EXPECT_TRUE(page->supports_instant()); 154 } 155