| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/url_pattern/simple_url_pattern_matcher.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/logging.h" |
| #include "base/strings/strcat.h" |
| #include "base/test/gmock_expected_support.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| namespace url_pattern { |
| |
| namespace { |
| |
| class PatternInitMatcher : public testing::MatcherInterface< |
| const SimpleUrlPatternMatcher::PatternInit&> { |
| public: |
| PatternInitMatcher(std::optional<std::string> protocol_matcher, |
| std::optional<std::string> username_matcher, |
| std::optional<std::string> password_matcher, |
| std::optional<std::string> hostname_matcher, |
| std::optional<std::string> port_matcher, |
| std::optional<std::string> pathname_matcher, |
| std::optional<std::string> search_matcher, |
| std::optional<std::string> hash_matcher) |
| : protocol_matcher_(std::move(protocol_matcher)), |
| username_matcher_(std::move(username_matcher)), |
| password_matcher_(std::move(password_matcher)), |
| hostname_matcher_(std::move(hostname_matcher)), |
| port_matcher_(std::move(port_matcher)), |
| pathname_matcher_(std::move(pathname_matcher)), |
| search_matcher_(std::move(search_matcher)), |
| hash_matcher_(std::move(hash_matcher)) {} |
| ~PatternInitMatcher() override = default; |
| |
| PatternInitMatcher(const PatternInitMatcher&) = delete; |
| PatternInitMatcher& operator=(const PatternInitMatcher&) = delete; |
| PatternInitMatcher(PatternInitMatcher&&) = delete; |
| PatternInitMatcher& operator=(PatternInitMatcher&&) = delete; |
| |
| bool MatchAndExplain( |
| const SimpleUrlPatternMatcher::PatternInit& pattern, |
| testing::MatchResultListener* result_listener) const override { |
| return ExplainMatchResult( |
| testing::AllOf( |
| testing::Property("protocol", |
| &SimpleUrlPatternMatcher::PatternInit::protocol, |
| testing::Eq(protocol_matcher_)), |
| testing::Property("username", |
| &SimpleUrlPatternMatcher::PatternInit::username, |
| testing::Eq(username_matcher_)), |
| testing::Property("password", |
| &SimpleUrlPatternMatcher::PatternInit::password, |
| testing::Eq(password_matcher_)), |
| testing::Property("hostname", |
| &SimpleUrlPatternMatcher::PatternInit::hostname, |
| testing::Eq(hostname_matcher_)), |
| testing::Property("port", |
| &SimpleUrlPatternMatcher::PatternInit::port, |
| testing::Eq(port_matcher_)), |
| testing::Property("pathname", |
| &SimpleUrlPatternMatcher::PatternInit::pathname, |
| testing::Eq(pathname_matcher_)), |
| testing::Property("search", |
| &SimpleUrlPatternMatcher::PatternInit::search, |
| testing::Eq(search_matcher_)), |
| testing::Property("hash", |
| &SimpleUrlPatternMatcher::PatternInit::hash, |
| testing::Eq(hash_matcher_))), |
| pattern, result_listener); |
| } |
| |
| void DescribeTo(std::ostream* os) const override { |
| *os << "matches "; |
| Describe(*os); |
| } |
| |
| void DescribeNegationTo(std::ostream* os) const override { |
| *os << "does not match "; |
| Describe(*os); |
| } |
| |
| private: |
| void Describe(std::ostream& os) const { |
| os << "PatternInit {\n" |
| << " protocol: " << testing::PrintToString(protocol_matcher_) << "\n" |
| << " username: " << testing::PrintToString(username_matcher_) << "\n" |
| << " password: " << testing::PrintToString(password_matcher_) << "\n" |
| << " hostname: " << testing::PrintToString(hostname_matcher_) << "\n" |
| << " port: " << testing::PrintToString(port_matcher_) << "\n" |
| << " pathname: " << testing::PrintToString(pathname_matcher_) << "\n" |
| << " search: " << testing::PrintToString(search_matcher_) << "\n" |
| << " hash: " << testing::PrintToString(hash_matcher_) << "\n" |
| << "}"; |
| } |
| |
| const std::optional<std::string> protocol_matcher_; |
| const std::optional<std::string> username_matcher_; |
| const std::optional<std::string> password_matcher_; |
| const std::optional<std::string> hostname_matcher_; |
| const std::optional<std::string> port_matcher_; |
| const std::optional<std::string> pathname_matcher_; |
| const std::optional<std::string> search_matcher_; |
| const std::optional<std::string> hash_matcher_; |
| }; |
| |
| testing::Matcher<const SimpleUrlPatternMatcher::PatternInit&> ExpectPatternInit( |
| std::optional<std::string> protocol, |
| std::optional<std::string> username, |
| std::optional<std::string> password, |
| std::optional<std::string> hostname, |
| std::optional<std::string> port, |
| std::optional<std::string> pathname, |
| std::optional<std::string> search, |
| std::optional<std::string> hash) { |
| return testing::Matcher<const SimpleUrlPatternMatcher::PatternInit&>( |
| new PatternInitMatcher(std::move(protocol), std::move(username), |
| std::move(password), std::move(hostname), |
| std::move(port), std::move(pathname), |
| std::move(search), std::move(hash))); |
| } |
| |
| } // namespace |
| |
| class SimpleUrlPatternMatcherTest : public testing::Test { |
| public: |
| SimpleUrlPatternMatcherTest() = default; |
| ~SimpleUrlPatternMatcherTest() override = default; |
| |
| protected: |
| static base::expected<SimpleUrlPatternMatcher::PatternInit, std::string> |
| CreatePatternInit(const std::string_view& url_pattern, const GURL& base_url) { |
| return SimpleUrlPatternMatcher::CreatePatternInit( |
| url_pattern, &base_url, |
| /*protocol_matcher_out*=*/nullptr, |
| /*should_treat_as_standard_url_out=*/nullptr); |
| } |
| static base::expected<std::unique_ptr<SimpleUrlPatternMatcher>, std::string> |
| CreateMatcher(const std::string_view& constructor_string, |
| const GURL& base_url) { |
| return SimpleUrlPatternMatcher::Create(constructor_string, &base_url); |
| } |
| |
| static base::expected<std::unique_ptr<SimpleUrlPatternMatcher>, std::string> |
| CreateMatcherWithoutBaseUrl(const std::string_view& constructor_string) { |
| return SimpleUrlPatternMatcher::Create(constructor_string, nullptr); |
| } |
| }; |
| |
| TEST_F(SimpleUrlPatternMatcherTest, Create) { |
| struct { |
| std::string_view constructor_string; |
| std::string_view base_url; |
| std::optional<testing::Matcher<const SimpleUrlPatternMatcher::PatternInit&>> |
| expected_pattern; |
| std::optional<std::string_view> expected_error; |
| std::vector<std::string_view> match_urls; |
| std::vector<std::string_view> non_match_urls; |
| } test_cases[] = { |
| |
| // Test cases for SimpleUrlPatternMatcher creation success |
| |
| // Absolute path |
| {.constructor_string = "/foo", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/foo", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/foo", "https://example.com/foo?bar"}, |
| .non_match_urls = {"https://example.com/bar", "https://example.com/foo/", |
| "https://example.com/foo/baz"}}, |
| |
| // Absolute path ending with / |
| {.constructor_string = "/foo/", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/foo/", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/foo/", |
| "https://example.com/foo/?bar"}, |
| .non_match_urls = {"https://example.com/foo", |
| "https://example.com/foo?bar", |
| "https://example.com/foo/baz"}}, |
| |
| // Relative path |
| {.constructor_string = "hoge", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/foo/hoge", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/foo/hoge", |
| "https://example.com/foo/hoge?bar"}, |
| .non_match_urls = {"https://example.com/hoge", |
| "https://example.com/hoge/baz"}}, |
| |
| // Relative path ending with / |
| {.constructor_string = "hoge/", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/foo/hoge/", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/foo/hoge/", |
| "https://example.com/foo/hoge/?bar"}, |
| .non_match_urls = {"https://example.com/hoge", |
| "https://example.com/hoge?bar"}}, |
| |
| // Absolute URL |
| {.constructor_string = "https://example.com/piyo/fuga", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/piyo/fuga", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/piyo/fuga", |
| "https://example.com/piyo/fuga?bar"}, |
| .non_match_urls = {"https://example.com/foo/", |
| "https://example.com/foo/piyo/fuga", |
| "https://example.com/piyo"}}, |
| |
| // Absolute URL with different hostname |
| {.constructor_string = "https://example.net/piyo/fuga", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.net", |
| /*port=*/"", /*pathname=*/"/piyo/fuga", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.net/piyo/fuga", |
| "https://example.net/piyo/fuga?bar"}, |
| .non_match_urls = {"https://example.com/foo/", |
| "https://example.com/foo/piyo/fuga"}}, |
| |
| // Absolute URL with a default port |
| {.constructor_string = "https://example.com:443/piyo/fuga", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/piyo/fuga", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/piyo/fuga", |
| "https://example.com:443/piyo/fuga"}, |
| .non_match_urls = {"https://example.com:444/piyo/fuga/", |
| "https://example.com:80/piyo/fuga"}}, |
| |
| // Absolute URL with a non-default port |
| {.constructor_string = "https://example.com:444/piyo/fuga", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"444", /*pathname=*/"/piyo/fuga", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com:444/piyo/fuga"}, |
| .non_match_urls = {"https://example.com/piyo/fuga/", |
| "https://example.com:443/piyo/fuga", |
| "https://example.com:80/piyo/fuga"}}, |
| |
| // Empty pathname |
| {.constructor_string = "https://example.com", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/std::nullopt, |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com", "https://example.com/piyo/"}, |
| .non_match_urls = {"https://example.net/"}}, |
| |
| // pathname = `/` |
| {.constructor_string = "https://example.com/", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com"}, |
| .non_match_urls = {"https://example.net/", "https://example.com/piyo/"}}, |
| |
| // Relative path with a query string |
| {.constructor_string = "hoge?*", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/foo/hoge", |
| /*search=*/"*", |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/foo/hoge", |
| "https://example.com/foo/hoge?bar"}, |
| .non_match_urls = {"https://example.com/hoge", |
| "https://example.com/hoge/baz"}}, |
| |
| // Relative path with a query string with a non-standard base_url |
| {.constructor_string = "hoge?*", |
| .base_url = "non-standard:example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"non-standard", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"", |
| /*port=*/"", /*pathname=*/"hoge", |
| /*search=*/"*", |
| /*hash=*/std::nullopt), |
| .match_urls = {"non-standard:hoge", "non-standard:hoge?bar"}, |
| .non_match_urls = {"non-standard:example.com/foo/hoge", |
| "non-standard:example.com/foo/hoge?bar"}}, |
| |
| // Pattern group hostname |
| {.constructor_string = "https://{:subdomain.}?example.com/piyo/fuga", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"{:subdomain.}?example.com", |
| /*port=*/"", /*pathname=*/"/piyo/fuga", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/piyo/fuga", |
| "https://a.example.com/piyo/fuga"}, |
| .non_match_urls = {"https://example.net/piyo/fuga"}}, |
| |
| // Escaped pathname |
| {.constructor_string = "\\/piyo\\/fuga", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"\\/piyo\\/fuga", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/piyo/fuga", |
| "https://example.com/piyo/fuga?bar"}, |
| .non_match_urls = {"https://example.com\\/piyo/fuga"}}, |
| |
| // No slash in the non-standard base URL's pathname |
| {.constructor_string = "hoge/piyo", |
| .base_url = "non-standard:", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"non-standard", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"", |
| /*port=*/"", /*pathname=*/"hoge/piyo", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"non-standard:hoge/piyo", "non-standard:hoge/piyo"}, |
| .non_match_urls = {"https://hoge/piyo"}}, |
| |
| // Empty constructor string |
| {.constructor_string = "", |
| .base_url = "https://example.com/foo/bar.html", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/foo/", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/foo/", |
| "https://example.com/foo/?bar"}, |
| .non_match_urls = {"https://example.com/foo", |
| "https://example.com/foo/bar", |
| "https://example.com/foo/bar/baz"}}, |
| |
| // Test cases for SimpleUrlPatternMatcher creation failure |
| |
| // Invalid constructor string (pathname) |
| {.constructor_string = "{", |
| .base_url = "https://urlpattern.example/foo/bar", |
| .expected_error = "Failed to parse pattern for pathname"}, |
| |
| // Invalid constructor string (protocol) |
| {.constructor_string = "\t://example.com/", |
| .base_url = "https://urlpattern.example/foo/bar", |
| .expected_error = "Failed to parse pattern for protocol"}, |
| |
| // Unsupported regexp group |
| {.constructor_string = "/(\\d+)/", |
| .base_url = "https://urlpattern.example/foo/bar", |
| .expected_error = "Regexp groups are not supported for pathname"}, |
| |
| // Invalid base URL |
| {.constructor_string = "/foo/", |
| .base_url = "", |
| .expected_error = "Invalid base URL"}}; |
| |
| for (const auto& test : test_cases) { |
| SCOPED_TRACE( |
| base::StrCat({"constructor_string: \"", test.constructor_string, |
| "\", base_url: \"", test.base_url, "\""})); |
| if (!test.expected_error) { |
| ASSERT_OK_AND_ASSIGN(auto matcher, CreateMatcher(test.constructor_string, |
| GURL(test.base_url))); |
| ASSERT_OK_AND_ASSIGN( |
| auto pattern, |
| CreatePatternInit(test.constructor_string, GURL(test.base_url))); |
| EXPECT_THAT(pattern, *test.expected_pattern); |
| for (const auto& match_url : test.match_urls) { |
| EXPECT_TRUE(matcher->Match(GURL(match_url))) << match_url; |
| } |
| for (const auto& non_match_url : test.non_match_urls) { |
| EXPECT_FALSE(matcher->Match(GURL(non_match_url))) << non_match_url; |
| } |
| } else { |
| auto create_matcher_result = |
| CreateMatcher(test.constructor_string, GURL(test.base_url)); |
| EXPECT_FALSE(create_matcher_result.has_value()); |
| EXPECT_EQ(create_matcher_result.error(), test.expected_error); |
| } |
| } |
| } |
| |
| TEST_F(SimpleUrlPatternMatcherTest, CreateWithoutBaseUrl) { |
| struct { |
| std::string_view constructor_string; |
| std::optional<testing::Matcher<const SimpleUrlPatternMatcher::PatternInit&>> |
| expected_pattern; |
| std::optional<std::string_view> expected_error; |
| std::vector<std::string_view> match_urls; |
| std::vector<std::string_view> non_match_urls; |
| } test_cases[] = { |
| |
| // Test cases for SimpleUrlPatternMatcher creation success |
| |
| // Absolute URL |
| {.constructor_string = "https://example.com/piyo/fuga", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/piyo/fuga", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/piyo/fuga", |
| "https://example.com/piyo/fuga?bar"}, |
| .non_match_urls = {"https://example.com/foo/", |
| "https://example.com/foo/piyo/fuga", |
| "https://example.com/piyo"}}, |
| |
| // Absolute URL with absolute pathname |
| {.constructor_string = "https://example.com/foo", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/foo", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/foo", "https://example.com/foo?bar"}, |
| .non_match_urls = {"https://example.com/bar"}}, |
| |
| // Absolute URL with different hostname |
| {.constructor_string = "https://example.net/piyo/fuga", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.net", |
| /*port=*/"", /*pathname=*/"/piyo/fuga", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.net/piyo/fuga", |
| "https://example.net/piyo/fuga?bar"}, |
| .non_match_urls = {"https://example.com/foo/", |
| "https://example.com/foo/piyo/fuga"}}, |
| |
| // Absolute URL with a default port |
| {.constructor_string = "https://example.com:443/piyo/fuga", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/piyo/fuga", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com/piyo/fuga", |
| "https://example.com:443/piyo/fuga"}, |
| .non_match_urls = {"https://example.com:444/piyo/fuga/", |
| "https://example.com:80/piyo/fuga"}}, |
| |
| // Absolute URL with a non-default port |
| {.constructor_string = "https://example.com:444/piyo/fuga", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"444", /*pathname=*/"/piyo/fuga", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com:444/piyo/fuga"}, |
| .non_match_urls = {"https://example.com/piyo/fuga/", |
| "https://example.com:443/piyo/fuga", |
| "https://example.com:80/piyo/fuga"}}, |
| |
| // Empty pathname |
| {.constructor_string = "https://example.com", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/std::nullopt, |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com", "https://example.com/piyo/"}, |
| .non_match_urls = {"https://example.net/"}}, |
| |
| // pathname = `/` |
| {.constructor_string = "https://example.com/", |
| .expected_pattern = ExpectPatternInit( |
| /*protocol=*/"https", /*username=*/std::nullopt, |
| /*password=*/std::nullopt, /*hostname=*/"example.com", |
| /*port=*/"", /*pathname=*/"/", |
| /*search=*/std::nullopt, |
| /*hash=*/std::nullopt), |
| .match_urls = {"https://example.com"}, |
| .non_match_urls = {"https://example.net/", "https://example.com/piyo/"}}, |
| |
| // Test cases for SimpleUrlPatternMatcher creation failure |
| |
| // Relative path with a query string with a non-standard protocol |
| {.constructor_string = "non-standard:hoge?*", |
| .expected_error = "Protocol may not be omitted"}, |
| |
| // Escaped pathname |
| {.constructor_string = "\\/piyo\\/fuga", |
| .expected_error = "Protocol may not be omitted"}, |
| |
| // No slash in the non-standard base URL's pathname |
| {.constructor_string = "non-standard:hoge/piyo", |
| .expected_error = "Protocol may not be omitted"}, |
| |
| // Relative path |
| {.constructor_string = "/foo", |
| .expected_error = "Protocol may not be omitted"}, |
| |
| // Relative path ending with / |
| {.constructor_string = "/foo/", |
| .expected_error = "Protocol may not be omitted"}, |
| |
| // Relative path |
| {.constructor_string = "hoge", |
| .expected_error = "Protocol may not be omitted"}, |
| |
| // Relative path ending with / |
| {.constructor_string = "hoge/", |
| .expected_error = "Protocol may not be omitted"}, |
| |
| // Empty constructor string |
| {.constructor_string = "", |
| .expected_error = "Protocol may not be omitted"}, |
| |
| // Invalid constructor string (pathname) |
| {.constructor_string = "https://example.com/{", |
| .expected_error = "Failed to parse pattern for pathname"}, |
| |
| // Invalid constructor string (protocol) |
| {.constructor_string = "\t://example.com/", |
| .expected_error = "Failed to parse pattern for protocol"}, |
| |
| // Unsupported regexp group |
| {.constructor_string = "https://example.com/(\\d+)/", |
| .expected_error = "Regexp groups are not supported for pathname"}}; |
| |
| for (const auto& test : test_cases) { |
| SCOPED_TRACE(base::StrCat( |
| {"constructor_string: \"", test.constructor_string, "\""})); |
| if (!test.expected_error) { |
| ASSERT_OK_AND_ASSIGN( |
| auto matcher, CreateMatcherWithoutBaseUrl(test.constructor_string)); |
| for (const auto& match_url : test.match_urls) { |
| EXPECT_TRUE(matcher->Match(GURL(match_url))) << match_url; |
| } |
| for (const auto& non_match_url : test.non_match_urls) { |
| EXPECT_FALSE(matcher->Match(GURL(non_match_url))) << non_match_url; |
| } |
| } else { |
| auto create_matcher_result = |
| CreateMatcherWithoutBaseUrl(test.constructor_string); |
| EXPECT_FALSE(create_matcher_result.has_value()); |
| EXPECT_EQ(create_matcher_result.error(), *test.expected_error); |
| } |
| } |
| } |
| } // namespace url_pattern |