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 MOCK_METHOD1(InstantPageLoadFailed, void(content::WebContents* contents)); 47 }; 48 49 } // namespace 50 51 class InstantPageTest : public ChromeRenderViewHostTestHarness { 52 public: 53 virtual void SetUp() OVERRIDE; 54 55 bool MessageWasSent(uint32 id) { 56 return process()->sink().GetFirstMessageMatching(id) != NULL; 57 } 58 59 scoped_ptr<InstantPage> page; 60 FakePageDelegate delegate; 61 }; 62 63 void InstantPageTest::SetUp() { 64 ChromeRenderViewHostTestHarness::SetUp(); 65 SearchTabHelper::CreateForWebContents(web_contents()); 66 } 67 68 TEST_F(InstantPageTest, IsLocal) { 69 page.reset(new InstantPage(&delegate, "", NULL, false)); 70 EXPECT_FALSE(page->supports_instant()); 71 EXPECT_FALSE(page->IsLocal()); 72 page->SetContents(web_contents()); 73 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl)); 74 EXPECT_TRUE(page->IsLocal()); 75 NavigateAndCommit(GURL("http://example.com")); 76 EXPECT_FALSE(page->IsLocal()); 77 } 78 79 TEST_F(InstantPageTest, DetermineIfPageSupportsInstant_Local) { 80 page.reset(new InstantPage(&delegate, "", NULL, false)); 81 EXPECT_FALSE(page->supports_instant()); 82 page->SetContents(web_contents()); 83 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl)); 84 EXPECT_TRUE(page->IsLocal()); 85 EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), true)) 86 .Times(1); 87 SearchTabHelper::FromWebContents(web_contents())-> 88 DetermineIfPageSupportsInstant(); 89 EXPECT_TRUE(page->supports_instant()); 90 } 91 92 TEST_F(InstantPageTest, DetermineIfPageSupportsInstant_NonLocal) { 93 page.reset(new InstantPage(&delegate, "", NULL, false)); 94 EXPECT_FALSE(page->supports_instant()); 95 page->SetContents(web_contents()); 96 NavigateAndCommit(GURL("chrome-search://foo/bar")); 97 EXPECT_FALSE(page->IsLocal()); 98 process()->sink().ClearMessages(); 99 SearchTabHelper::FromWebContents(web_contents())-> 100 DetermineIfPageSupportsInstant(); 101 const IPC::Message* message = process()->sink().GetFirstMessageMatching( 102 ChromeViewMsg_DetermineIfPageSupportsInstant::ID); 103 ASSERT_TRUE(message != NULL); 104 EXPECT_EQ(web_contents()->GetRoutingID(), message->routing_id()); 105 } 106 107 TEST_F(InstantPageTest, PageURLDoesntBelongToInstantRenderer) { 108 page.reset(new InstantPage(&delegate, "", NULL, false)); 109 EXPECT_FALSE(page->supports_instant()); 110 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl)); 111 page->SetContents(web_contents()); 112 113 // Navigate to a page URL that doesn't belong to Instant renderer. 114 // SearchTabHelper::DeterminerIfPageSupportsInstant() should return 115 // immediately without dispatching any message to the renderer. 116 NavigateAndCommit(GURL("http://www.example.com")); 117 EXPECT_FALSE(page->IsLocal()); 118 process()->sink().ClearMessages(); 119 EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), false)) 120 .Times(1); 121 122 SearchTabHelper::FromWebContents(web_contents())-> 123 DetermineIfPageSupportsInstant(); 124 const IPC::Message* message = process()->sink().GetFirstMessageMatching( 125 ChromeViewMsg_DetermineIfPageSupportsInstant::ID); 126 ASSERT_TRUE(message == NULL); 127 EXPECT_FALSE(page->supports_instant()); 128 } 129 130 // Test to verify that ChromeViewMsg_DetermineIfPageSupportsInstant message 131 // reply handler updates the instant support state in InstantPage. 132 TEST_F(InstantPageTest, PageSupportsInstant) { 133 page.reset(new InstantPage(&delegate, "", NULL, false)); 134 EXPECT_FALSE(page->supports_instant()); 135 page->SetContents(web_contents()); 136 NavigateAndCommit(GURL("chrome-search://foo/bar")); 137 process()->sink().ClearMessages(); 138 SearchTabHelper::FromWebContents(web_contents())-> 139 DetermineIfPageSupportsInstant(); 140 const IPC::Message* message = process()->sink().GetFirstMessageMatching( 141 ChromeViewMsg_DetermineIfPageSupportsInstant::ID); 142 ASSERT_TRUE(message != NULL); 143 EXPECT_EQ(web_contents()->GetRoutingID(), message->routing_id()); 144 145 EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), true)) 146 .Times(1); 147 148 // Assume the page supports instant. Invoke the message reply handler to make 149 // sure the InstantPage is notified about the instant support state. 150 const content::NavigationEntry* entry = 151 web_contents()->GetController().GetLastCommittedEntry(); 152 EXPECT_TRUE(entry); 153 SearchTabHelper::FromWebContents(web_contents())->InstantSupportChanged(true); 154 EXPECT_TRUE(page->supports_instant()); 155 } 156 157 TEST_F(InstantPageTest, AppropriateMessagesSentToIncognitoPages) { 158 page.reset(new InstantPage(&delegate, "", NULL, true)); 159 page->SetContents(web_contents()); 160 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl)); 161 process()->sink().ClearMessages(); 162 163 // Incognito pages should get these messages. 164 page->sender()->SetOmniboxBounds(gfx::Rect()); 165 EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxMarginChange::ID)); 166 167 // Incognito pages should not get any others. 168 page->sender()->FocusChanged( 169 OMNIBOX_FOCUS_NONE, OMNIBOX_FOCUS_CHANGE_EXPLICIT); 170 EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxFocusChanged::ID)); 171 172 page->sender()->SetInputInProgress(false); 173 EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxSetInputInProgress::ID)); 174 } 175