OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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/extensions/api/declarative_content/declarative_content_
css_condition_tracker.h" |
| 6 |
| 7 #include "base/memory/scoped_ptr.h" |
| 8 #include "base/run_loop.h" |
| 9 #include "chrome/test/base/testing_profile.h" |
| 10 #include "content/public/browser/navigation_details.h" |
| 11 #include "content/public/browser/render_view_host.h" |
| 12 #include "content/public/browser/web_contents.h" |
| 13 #include "content/public/test/browser_test_utils.h" |
| 14 #include "content/public/test/mock_render_process_host.h" |
| 15 #include "content/public/test/test_browser_thread_bundle.h" |
| 16 #include "content/public/test/test_renderer_host.h" |
| 17 #include "content/public/test/web_contents_tester.h" |
| 18 #include "extensions/common/extension_messages.h" |
| 19 #include "testing/gmock/include/gmock/gmock.h" |
| 20 #include "testing/gtest/include/gtest/gtest.h" |
| 21 |
| 22 namespace extensions { |
| 23 |
| 24 using testing::UnorderedElementsAreArray; |
| 25 |
| 26 class DeclarativeContentCssConditionTrackerTest : public testing::Test { |
| 27 public: |
| 28 DeclarativeContentCssConditionTrackerTest() : profile_(new TestingProfile) {} |
| 29 |
| 30 ~DeclarativeContentCssConditionTrackerTest() override { |
| 31 // MockRenderProcessHosts are deleted from the message loop, and their |
| 32 // deletion must complete before RenderViewHostTestEnabler's destructor is |
| 33 // run. |
| 34 base::RunLoop().RunUntilIdle(); |
| 35 } |
| 36 |
| 37 protected: |
| 38 class Delegate : public DeclarativeContentCssConditionTrackerDelegate { |
| 39 public: |
| 40 Delegate() : evaluation_requests_(0) {} |
| 41 |
| 42 int evaluation_requests() { return evaluation_requests_; } |
| 43 |
| 44 // DeclarativeContentCssConditionTrackerDelegate: |
| 45 void RequestEvaluation(content::WebContents* contents) override { |
| 46 ++evaluation_requests_; |
| 47 } |
| 48 |
| 49 bool ShouldManageConditionsForBrowserContext( |
| 50 content::BrowserContext* context) override { |
| 51 return true; |
| 52 } |
| 53 |
| 54 private: |
| 55 int evaluation_requests_; |
| 56 |
| 57 DISALLOW_COPY_AND_ASSIGN(Delegate); |
| 58 }; |
| 59 |
| 60 // Creates a new WebContents and retains ownership. |
| 61 scoped_ptr<content::WebContents> MakeTab() { |
| 62 return make_scoped_ptr(content::WebContentsTester::CreateTestWebContents( |
| 63 profile_.get(), |
| 64 nullptr)); |
| 65 } |
| 66 |
| 67 // Expect an ExtensionMsg_WatchPages message in |sink| with |selectors| as the |
| 68 // param, after invoking |func|. |
| 69 template <class Func> |
| 70 void ExpectWatchPagesMessage(IPC::TestSink& sink, |
| 71 const std::set<std::string>& selectors, |
| 72 const Func& func) { |
| 73 sink.ClearMessages(); |
| 74 func(); |
| 75 EXPECT_EQ(1u, sink.message_count()); |
| 76 const IPC::Message* message = |
| 77 sink.GetUniqueMessageMatching(ExtensionMsg_WatchPages::ID); |
| 78 ASSERT_TRUE(message); |
| 79 ExtensionMsg_WatchPages::Param params; |
| 80 ExtensionMsg_WatchPages::Read(message, ¶ms); |
| 81 EXPECT_THAT(base::get<0>(params), UnorderedElementsAreArray(selectors)); |
| 82 } |
| 83 |
| 84 // Sends an OnWatchedPageChange message to the tab. |
| 85 void SendOnWatchedPageChangeMessage( |
| 86 content::WebContents* tab, |
| 87 const std::vector<std::string>& selectors) { |
| 88 ExtensionHostMsg_OnWatchedPageChange page_change(tab->GetRoutingID(), |
| 89 selectors); |
| 90 content::MockRenderProcessHost* process = |
| 91 static_cast<content::MockRenderProcessHost*>( |
| 92 tab->GetRenderViewHost()->GetProcess()); |
| 93 |
| 94 EXPECT_TRUE(process->OnMessageReceived(page_change)); |
| 95 } |
| 96 |
| 97 Profile* profile() { return profile_.get(); } |
| 98 Delegate* delegate() { return &delegate_; } |
| 99 |
| 100 private: |
| 101 content::TestBrowserThreadBundle thread_bundle_; |
| 102 |
| 103 // Enables MockRenderProcessHosts. |
| 104 content::RenderViewHostTestEnabler render_view_host_test_enabler_; |
| 105 |
| 106 const scoped_ptr<TestingProfile> profile_; |
| 107 Delegate delegate_; |
| 108 |
| 109 DISALLOW_COPY_AND_ASSIGN(DeclarativeContentCssConditionTrackerTest); |
| 110 }; |
| 111 |
| 112 // Tests the basic flow of operations on the |
| 113 // DeclarativeContentCssConditionTracker. |
| 114 TEST_F(DeclarativeContentCssConditionTrackerTest, Basic) { |
| 115 DeclarativeContentCssConditionTracker tracker(profile(), delegate()); |
| 116 int expected_evaluation_requests = 0; |
| 117 |
| 118 const scoped_ptr<content::WebContents> tab = MakeTab(); |
| 119 tracker.TrackForWebContents(tab.get()); |
| 120 EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests()); |
| 121 |
| 122 content::MockRenderProcessHost* process = |
| 123 static_cast<content::MockRenderProcessHost*>( |
| 124 tab->GetRenderViewHost()->GetProcess()); |
| 125 |
| 126 // Check that calling SetWatchedCssSelectors sends a WatchPages message with |
| 127 // the selectors to the tab's RenderProcessHost. |
| 128 std::set<std::string> watched_selectors; |
| 129 watched_selectors.insert("a"); |
| 130 watched_selectors.insert("div"); |
| 131 ExpectWatchPagesMessage(process->sink(), watched_selectors, |
| 132 [&tracker, &watched_selectors]() { |
| 133 tracker.SetWatchedCssSelectors(watched_selectors); |
| 134 }); |
| 135 EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests()); |
| 136 |
| 137 // Check that receiving an OnWatchedPageChange message from the tab results in |
| 138 // a request for condition evaluation. |
| 139 const std::vector<std::string> matched_selectors(1, "div"); |
| 140 SendOnWatchedPageChangeMessage(tab.get(), matched_selectors); |
| 141 EXPECT_EQ(++expected_evaluation_requests, delegate()->evaluation_requests()); |
| 142 |
| 143 // Check that GetMatchingCssSelectors produces the same matched selectors as |
| 144 // were sent by the OnWatchedPageChange message. |
| 145 base::hash_set<std::string> matching_selectors; |
| 146 tracker.GetMatchingCssSelectors(tab.get(), &matching_selectors); |
| 147 EXPECT_THAT(matching_selectors, |
| 148 UnorderedElementsAreArray(matched_selectors)); |
| 149 EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests()); |
| 150 |
| 151 // Check that an in-page navigation has no effect on the matching selectors. |
| 152 { |
| 153 content::LoadCommittedDetails details; |
| 154 details.is_in_page = true; |
| 155 content::FrameNavigateParams params; |
| 156 tracker.OnWebContentsNavigation(tab.get(), details, params); |
| 157 matching_selectors.clear(); |
| 158 tracker.GetMatchingCssSelectors(tab.get(), &matching_selectors); |
| 159 EXPECT_THAT(matching_selectors, |
| 160 UnorderedElementsAreArray(matched_selectors)); |
| 161 EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests()); |
| 162 } |
| 163 |
| 164 // Check that a non in-page navigation clears the matching selectors and |
| 165 // requests condition evaluation. |
| 166 { |
| 167 content::LoadCommittedDetails details; |
| 168 details.is_in_page = false; |
| 169 content::FrameNavigateParams params; |
| 170 tracker.OnWebContentsNavigation(tab.get(), details, params); |
| 171 matching_selectors.clear(); |
| 172 tracker.GetMatchingCssSelectors(tab.get(), &matching_selectors); |
| 173 EXPECT_TRUE(matching_selectors.empty()); |
| 174 EXPECT_EQ(++expected_evaluation_requests, |
| 175 delegate()->evaluation_requests()); |
| 176 } |
| 177 } |
| 178 |
| 179 // https://crbug.com/497586 |
| 180 TEST_F(DeclarativeContentCssConditionTrackerTest, WebContentsOutlivesTracker) { |
| 181 const scoped_ptr<content::WebContents> tab = MakeTab(); |
| 182 |
| 183 { |
| 184 DeclarativeContentCssConditionTracker tracker(profile(), delegate()); |
| 185 tracker.TrackForWebContents(tab.get()); |
| 186 } |
| 187 } |
| 188 |
| 189 } // namespace extensions |
OLD | NEW |