blob: 96f33b198f9ad8cc8e844cd501495b484fa4dfd1 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/context_menu_helpers.h"
#include "content/public/browser/context_menu_params.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/test/test_renderer_host.h"
#include "extensions/common/url_pattern.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h"
#include "url/gurl.h"
using extensions::context_menu_helpers::ExtensionContextAndPatternMatch;
namespace extensions {
namespace {
// Generates a ContextMenuParams that matches the specified contexts.
content::ContextMenuParams CreateParams(int contexts) {
content::ContextMenuParams rv;
rv.is_editable = false;
rv.media_type = blink::mojom::ContextMenuDataMediaType::kNone;
rv.page_url = GURL("http://test.page/");
rv.frame_url = GURL("http://test.page/");
rv.frame_origin = url::Origin::Create(rv.frame_url);
static constexpr char16_t selected_text[] = u"sel";
if (contexts & MenuItem::SELECTION) {
rv.selection_text = selected_text;
}
if (contexts & MenuItem::LINK) {
rv.link_url = GURL("http://test.link/");
}
if (contexts & MenuItem::EDITABLE) {
rv.is_editable = true;
}
if (contexts & MenuItem::IMAGE) {
rv.src_url = GURL("http://test.image/");
rv.media_type = blink::mojom::ContextMenuDataMediaType::kImage;
}
if (contexts & MenuItem::VIDEO) {
rv.src_url = GURL("http://test.video/");
rv.media_type = blink::mojom::ContextMenuDataMediaType::kVideo;
}
if (contexts & MenuItem::AUDIO) {
rv.src_url = GURL("http://test.audio/");
rv.media_type = blink::mojom::ContextMenuDataMediaType::kAudio;
}
if (contexts & MenuItem::FRAME) {
rv.is_subframe = true;
}
return rv;
}
// Generates a URLPatternSet with a single pattern
static URLPatternSet CreatePatternSet(const std::string& pattern) {
URLPattern target(URLPattern::SCHEME_HTTP);
target.Parse(pattern);
URLPatternSet rv;
rv.AddPattern(target);
return rv;
}
class TestNavigationDelegate : public content::WebContentsDelegate {
public:
TestNavigationDelegate() = default;
~TestNavigationDelegate() override = default;
content::WebContents* OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params,
base::OnceCallback<void(content::NavigationHandle&)>
navigation_handle_callback) override {
last_navigation_params_ = params;
return nullptr;
}
const std::optional<content::OpenURLParams>& last_navigation_params() {
return last_navigation_params_;
}
private:
std::optional<content::OpenURLParams> last_navigation_params_;
};
} // namespace
class ContextMenuHelpersTest : public testing::Test {
protected:
ContextMenuHelpersTest() = default;
ContextMenuHelpersTest(const ContextMenuHelpersTest&) = delete;
ContextMenuHelpersTest& operator=(const ContextMenuHelpersTest&) = delete;
private:
content::RenderViewHostTestEnabler rvh_test_enabler_;
};
TEST_F(ContextMenuHelpersTest, TargetIgnoredForPage) {
content::ContextMenuParams params = CreateParams(0);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::PAGE);
URLPatternSet patterns = CreatePatternSet("*://test.none/*");
EXPECT_TRUE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
TEST_F(ContextMenuHelpersTest, TargetCheckedForLink) {
content::ContextMenuParams params = CreateParams(MenuItem::LINK);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::PAGE);
contexts.Add(MenuItem::LINK);
URLPatternSet patterns = CreatePatternSet("*://test.none/*");
EXPECT_FALSE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
TEST_F(ContextMenuHelpersTest, TargetCheckedForImage) {
content::ContextMenuParams params = CreateParams(MenuItem::IMAGE);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::PAGE);
contexts.Add(MenuItem::IMAGE);
URLPatternSet patterns = CreatePatternSet("*://test.none/*");
EXPECT_FALSE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
TEST_F(ContextMenuHelpersTest, TargetCheckedForVideo) {
content::ContextMenuParams params = CreateParams(MenuItem::VIDEO);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::PAGE);
contexts.Add(MenuItem::VIDEO);
URLPatternSet patterns = CreatePatternSet("*://test.none/*");
EXPECT_FALSE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
TEST_F(ContextMenuHelpersTest, TargetCheckedForAudio) {
content::ContextMenuParams params = CreateParams(MenuItem::AUDIO);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::PAGE);
contexts.Add(MenuItem::AUDIO);
URLPatternSet patterns = CreatePatternSet("*://test.none/*");
EXPECT_FALSE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
TEST_F(ContextMenuHelpersTest, MatchWhenLinkedImageMatchesTarget) {
content::ContextMenuParams params =
CreateParams(MenuItem::IMAGE | MenuItem::LINK);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::LINK);
contexts.Add(MenuItem::IMAGE);
URLPatternSet patterns = CreatePatternSet("*://test.link/*");
EXPECT_TRUE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
TEST_F(ContextMenuHelpersTest, MatchWhenLinkedImageMatchesSource) {
content::ContextMenuParams params =
CreateParams(MenuItem::IMAGE | MenuItem::LINK);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::LINK);
contexts.Add(MenuItem::IMAGE);
URLPatternSet patterns = CreatePatternSet("*://test.image/*");
EXPECT_TRUE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
TEST_F(ContextMenuHelpersTest, NoMatchWhenLinkedImageMatchesNeither) {
content::ContextMenuParams params =
CreateParams(MenuItem::IMAGE | MenuItem::LINK);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::LINK);
contexts.Add(MenuItem::IMAGE);
URLPatternSet patterns = CreatePatternSet("*://test.none/*");
EXPECT_FALSE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
TEST_F(ContextMenuHelpersTest, TargetIgnoredForFrame) {
content::ContextMenuParams params = CreateParams(MenuItem::FRAME);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::FRAME);
URLPatternSet patterns = CreatePatternSet("*://test.none/*");
EXPECT_TRUE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
TEST_F(ContextMenuHelpersTest, TargetIgnoredForEditable) {
content::ContextMenuParams params = CreateParams(MenuItem::EDITABLE);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::EDITABLE);
URLPatternSet patterns = CreatePatternSet("*://test.none/*");
EXPECT_TRUE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
TEST_F(ContextMenuHelpersTest, TargetIgnoredForSelection) {
content::ContextMenuParams params = CreateParams(MenuItem::SELECTION);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::SELECTION);
URLPatternSet patterns = CreatePatternSet("*://test.none/*");
EXPECT_TRUE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
TEST_F(ContextMenuHelpersTest, TargetIgnoredForSelectionOnLink) {
content::ContextMenuParams params =
CreateParams(MenuItem::SELECTION | MenuItem::LINK);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::SELECTION);
contexts.Add(MenuItem::LINK);
URLPatternSet patterns = CreatePatternSet("*://test.none/*");
EXPECT_TRUE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
TEST_F(ContextMenuHelpersTest, TargetIgnoredForSelectionOnImage) {
content::ContextMenuParams params =
CreateParams(MenuItem::SELECTION | MenuItem::IMAGE);
MenuItem::ContextList contexts;
contexts.Add(MenuItem::SELECTION);
contexts.Add(MenuItem::IMAGE);
URLPatternSet patterns = CreatePatternSet("*://test.none/*");
EXPECT_TRUE(ExtensionContextAndPatternMatch(params, contexts, patterns));
}
} // namespace extensions