| Index: chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
|
| diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5ef2f043b2b07c4bf3115e5a85eddcea75c52740
|
| --- /dev/null
|
| +++ b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
|
| @@ -0,0 +1,189 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h"
|
| +
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/run_loop.h"
|
| +#include "chrome/test/base/testing_profile.h"
|
| +#include "content/public/browser/navigation_details.h"
|
| +#include "content/public/browser/render_view_host.h"
|
| +#include "content/public/browser/web_contents.h"
|
| +#include "content/public/test/browser_test_utils.h"
|
| +#include "content/public/test/mock_render_process_host.h"
|
| +#include "content/public/test/test_browser_thread_bundle.h"
|
| +#include "content/public/test/test_renderer_host.h"
|
| +#include "content/public/test/web_contents_tester.h"
|
| +#include "extensions/common/extension_messages.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace extensions {
|
| +
|
| +using testing::UnorderedElementsAreArray;
|
| +
|
| +class DeclarativeContentCssConditionTrackerTest : public testing::Test {
|
| + public:
|
| + DeclarativeContentCssConditionTrackerTest() : profile_(new TestingProfile) {}
|
| +
|
| + ~DeclarativeContentCssConditionTrackerTest() override {
|
| + // MockRenderProcessHosts are deleted from the message loop, and their
|
| + // deletion must complete before RenderViewHostTestEnabler's destructor is
|
| + // run.
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + protected:
|
| + class Delegate : public DeclarativeContentCssConditionTrackerDelegate {
|
| + public:
|
| + Delegate() : evaluation_requests_(0) {}
|
| +
|
| + int evaluation_requests() { return evaluation_requests_; }
|
| +
|
| + // DeclarativeContentCssConditionTrackerDelegate:
|
| + void RequestEvaluation(content::WebContents* contents) override {
|
| + ++evaluation_requests_;
|
| + }
|
| +
|
| + bool ShouldManageConditionsForBrowserContext(
|
| + content::BrowserContext* context) override {
|
| + return true;
|
| + }
|
| +
|
| + private:
|
| + int evaluation_requests_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Delegate);
|
| + };
|
| +
|
| + // Creates a new WebContents and retains ownership.
|
| + scoped_ptr<content::WebContents> MakeTab() {
|
| + return make_scoped_ptr(content::WebContentsTester::CreateTestWebContents(
|
| + profile_.get(),
|
| + nullptr));
|
| + }
|
| +
|
| + // Expect an ExtensionMsg_WatchPages message in |sink| with |selectors| as the
|
| + // param, after invoking |func|.
|
| + template <class Func>
|
| + void ExpectWatchPagesMessage(IPC::TestSink& sink,
|
| + const std::set<std::string>& selectors,
|
| + const Func& func) {
|
| + sink.ClearMessages();
|
| + func();
|
| + EXPECT_EQ(1u, sink.message_count());
|
| + const IPC::Message* message =
|
| + sink.GetUniqueMessageMatching(ExtensionMsg_WatchPages::ID);
|
| + ASSERT_TRUE(message);
|
| + ExtensionMsg_WatchPages::Param params;
|
| + ExtensionMsg_WatchPages::Read(message, ¶ms);
|
| + EXPECT_THAT(base::get<0>(params), UnorderedElementsAreArray(selectors));
|
| + }
|
| +
|
| + // Sends an OnWatchedPageChange message to the tab.
|
| + void SendOnWatchedPageChangeMessage(
|
| + content::WebContents* tab,
|
| + const std::vector<std::string>& selectors) {
|
| + ExtensionHostMsg_OnWatchedPageChange page_change(tab->GetRoutingID(),
|
| + selectors);
|
| + content::MockRenderProcessHost* process =
|
| + static_cast<content::MockRenderProcessHost*>(
|
| + tab->GetRenderViewHost()->GetProcess());
|
| +
|
| + EXPECT_TRUE(process->OnMessageReceived(page_change));
|
| + }
|
| +
|
| + Profile* profile() { return profile_.get(); }
|
| + Delegate* delegate() { return &delegate_; }
|
| +
|
| + private:
|
| + content::TestBrowserThreadBundle thread_bundle_;
|
| +
|
| + // Enables MockRenderProcessHosts.
|
| + content::RenderViewHostTestEnabler render_view_host_test_enabler_;
|
| +
|
| + const scoped_ptr<TestingProfile> profile_;
|
| + Delegate delegate_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(DeclarativeContentCssConditionTrackerTest);
|
| +};
|
| +
|
| +// Tests the basic flow of operations on the
|
| +// DeclarativeContentCssConditionTracker.
|
| +TEST_F(DeclarativeContentCssConditionTrackerTest, Basic) {
|
| + DeclarativeContentCssConditionTracker tracker(profile(), delegate());
|
| + int expected_evaluation_requests = 0;
|
| +
|
| + const scoped_ptr<content::WebContents> tab = MakeTab();
|
| + tracker.TrackForWebContents(tab.get());
|
| + EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests());
|
| +
|
| + content::MockRenderProcessHost* process =
|
| + static_cast<content::MockRenderProcessHost*>(
|
| + tab->GetRenderViewHost()->GetProcess());
|
| +
|
| + // Check that calling SetWatchedCssSelectors sends a WatchPages message with
|
| + // the selectors to the tab's RenderProcessHost.
|
| + std::set<std::string> watched_selectors;
|
| + watched_selectors.insert("a");
|
| + watched_selectors.insert("div");
|
| + ExpectWatchPagesMessage(process->sink(), watched_selectors,
|
| + [&tracker, &watched_selectors]() {
|
| + tracker.SetWatchedCssSelectors(watched_selectors);
|
| + });
|
| + EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests());
|
| +
|
| + // Check that receiving an OnWatchedPageChange message from the tab results in
|
| + // a request for condition evaluation.
|
| + const std::vector<std::string> matched_selectors(1, "div");
|
| + SendOnWatchedPageChangeMessage(tab.get(), matched_selectors);
|
| + EXPECT_EQ(++expected_evaluation_requests, delegate()->evaluation_requests());
|
| +
|
| + // Check that GetMatchingCssSelectors produces the same matched selectors as
|
| + // were sent by the OnWatchedPageChange message.
|
| + base::hash_set<std::string> matching_selectors;
|
| + tracker.GetMatchingCssSelectors(tab.get(), &matching_selectors);
|
| + EXPECT_THAT(matching_selectors,
|
| + UnorderedElementsAreArray(matched_selectors));
|
| + EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests());
|
| +
|
| + // Check that an in-page navigation has no effect on the matching selectors.
|
| + {
|
| + content::LoadCommittedDetails details;
|
| + details.is_in_page = true;
|
| + content::FrameNavigateParams params;
|
| + tracker.OnWebContentsNavigation(tab.get(), details, params);
|
| + matching_selectors.clear();
|
| + tracker.GetMatchingCssSelectors(tab.get(), &matching_selectors);
|
| + EXPECT_THAT(matching_selectors,
|
| + UnorderedElementsAreArray(matched_selectors));
|
| + EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests());
|
| + }
|
| +
|
| + // Check that a non in-page navigation clears the matching selectors and
|
| + // requests condition evaluation.
|
| + {
|
| + content::LoadCommittedDetails details;
|
| + details.is_in_page = false;
|
| + content::FrameNavigateParams params;
|
| + tracker.OnWebContentsNavigation(tab.get(), details, params);
|
| + matching_selectors.clear();
|
| + tracker.GetMatchingCssSelectors(tab.get(), &matching_selectors);
|
| + EXPECT_TRUE(matching_selectors.empty());
|
| + EXPECT_EQ(++expected_evaluation_requests,
|
| + delegate()->evaluation_requests());
|
| + }
|
| +}
|
| +
|
| +// https://crbug.com/497586
|
| +TEST_F(DeclarativeContentCssConditionTrackerTest, WebContentsOutlivesTracker) {
|
| + const scoped_ptr<content::WebContents> tab = MakeTab();
|
| +
|
| + {
|
| + DeclarativeContentCssConditionTracker tracker(profile(), delegate());
|
| + tracker.TrackForWebContents(tab.get());
|
| + }
|
| +}
|
| +
|
| +} // namespace extensions
|
|
|