/* * Copyright (c) 2025, Tim Ledbetter * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include TEST_CASE(public_suffix_matching_for_psl_rules) { struct TestCase { StringView input; bool is_public_suffix; Optional public_suffix; Optional registrable_domain; }; TestCase test_cases[] { { "com"sv, true, "com"sv, OptionalNone {} }, { "COM"sv, true, "com"sv, OptionalNone {} }, { ".com"sv, true, "com"sv, OptionalNone {} }, { "com."sv, true, "com."sv, OptionalNone {} }, { ".com."sv, true, "com."sv, OptionalNone {} }, { "..com."sv, true, "com."sv, OptionalNone {} }, { "example.com"sv, false, "com"sv, "example.com"sv }, { "EXAMPLE.COM"sv, false, "com"sv, "example.com"sv }, { ".example.com"sv, false, "com"sv, "example.com"sv }, { "www.example.com"sv, false, "com"sv, "example.com"sv }, { "sub.www.example.com"sv, false, "com"sv, "example.com"sv }, { "www.example.com."sv, false, "com."sv, "example.com."sv }, { "not-a-public-suffix.com"sv, false, "com"sv, "not-a-public-suffix.com"sv }, { "com.br"sv, true, "com.br"sv, OptionalNone {} }, { "not-a-public-suffix.com.br"sv, false, "com.br"sv, "not-a-public-suffix.com.br"sv }, { "co.uk"sv, true, "co.uk"sv, OptionalNone {} }, { "ac.uk"sv, true, "ac.uk"sv, OptionalNone {} }, { "gov.uk"sv, true, "gov.uk"sv, OptionalNone {} }, { "com.au"sv, true, "com.au"sv, OptionalNone {} }, { "co.jp"sv, true, "co.jp"sv, OptionalNone {} }, { "bbc.co.uk"sv, false, "co.uk"sv, "bbc.co.uk"sv }, { "www.bbc.co.uk"sv, false, "co.uk"sv, "bbc.co.uk"sv }, { "github.io"sv, true, "github.io"sv, OptionalNone {} }, { "ladybird.github.io"sv, false, "github.io"sv, "ladybird.github.io"sv }, { "whatwg.github.io"sv, false, "github.io"sv, "whatwg.github.io"sv }, { "公司.cn"sv, true, "xn--55qx5d.cn"sv, OptionalNone {} }, { "www.公司.cn"sv, false, "xn--55qx5d.cn"sv, "www.xn--55qx5d.cn"sv }, { "www.xn--55qx5d.cn"sv, false, "xn--55qx5d.cn"sv, "www.xn--55qx5d.cn"sv }, }; for (auto const& test_case : test_cases) { auto exclude_star_rule = URL::PublicSuffixData::IncludeStarRule::No; EXPECT_EQ(URL::PublicSuffixData::is_matching_public_suffix(test_case.input, exclude_star_rule), test_case.is_public_suffix); EXPECT_EQ(URL::PublicSuffixData::find_matching_public_suffix(test_case.input, exclude_star_rule), test_case.public_suffix); EXPECT_EQ(URL::PublicSuffixData::find_matching_registrable_domain(test_case.input, exclude_star_rule), test_case.registrable_domain); auto host = URL::Parser::parse_host(test_case.input); VERIFY(host.has_value()); EXPECT_EQ(URL::PublicSuffixData::is_matching_public_suffix(*host, exclude_star_rule), test_case.is_public_suffix); EXPECT_EQ(URL::PublicSuffixData::find_matching_public_suffix(*host, exclude_star_rule), test_case.public_suffix); EXPECT_EQ(URL::PublicSuffixData::find_matching_registrable_domain(*host, exclude_star_rule), test_case.registrable_domain); EXPECT_EQ(host->public_suffix(), test_case.public_suffix); EXPECT_EQ(host->registrable_domain(), test_case.registrable_domain); } } TEST_CASE(public_suffix_matching_without_psl_rule) { struct TestCase { StringView input; bool is_public_suffix_with_star_rule; Optional host_public_suffix; Optional host_registrable_domain; }; TestCase test_cases[] { { "foobar"sv, true, "foobar"sv, OptionalNone {} }, { "foobar."sv, true, "foobar."sv, OptionalNone {} }, { "not-a-public-suffix"sv, true, "not-a-public-suffix"sv, OptionalNone {} }, { "a.example"sv, false, "example"sv, "a.example"sv }, { "a.example."sv, false, "example."sv, "a.example."sv }, { "b.b.example"sv, false, "example"sv, "b.example"sv }, { "b.b.example."sv, false, "example."sv, "b.example."sv }, { "foo.not-a-public-suffix"sv, false, "not-a-public-suffix"sv, "foo.not-a-public-suffix"sv }, { "sub.foo.not-a-public-suffix"sv, false, "not-a-public-suffix"sv, "foo.not-a-public-suffix"sv }, { "إختبار"sv, true, "xn--kgbechtv"sv, OptionalNone {} }, { "example.إختبار"sv, false, "xn--kgbechtv"sv, "example.xn--kgbechtv"sv }, { "example.إختبار."sv, false, "xn--kgbechtv."sv, "example.xn--kgbechtv."sv }, { "sub.example.إختبار"sv, false, "xn--kgbechtv"sv, "example.xn--kgbechtv"sv }, }; for (auto const& test_case : test_cases) { auto exclude_star_rule = URL::PublicSuffixData::IncludeStarRule::No; auto include_star_rule = URL::PublicSuffixData::IncludeStarRule::Yes; EXPECT(!URL::PublicSuffixData::is_matching_public_suffix(test_case.input, exclude_star_rule)); EXPECT_EQ(URL::PublicSuffixData::find_matching_public_suffix(test_case.input, exclude_star_rule), OptionalNone {}); EXPECT_EQ(URL::PublicSuffixData::find_matching_registrable_domain(test_case.input, exclude_star_rule), OptionalNone {}); EXPECT_EQ(URL::PublicSuffixData::is_matching_public_suffix(test_case.input, include_star_rule), test_case.is_public_suffix_with_star_rule); EXPECT_EQ(URL::PublicSuffixData::find_matching_public_suffix(test_case.input, include_star_rule), test_case.host_public_suffix); EXPECT_EQ(URL::PublicSuffixData::find_matching_registrable_domain(test_case.input, include_star_rule), test_case.host_registrable_domain); auto host = URL::Parser::parse_host(test_case.input); VERIFY(host.has_value()); EXPECT(!URL::PublicSuffixData::is_matching_public_suffix(*host, exclude_star_rule)); EXPECT_EQ(URL::PublicSuffixData::find_matching_public_suffix(*host, exclude_star_rule), OptionalNone {}); EXPECT_EQ(URL::PublicSuffixData::find_matching_registrable_domain(*host, exclude_star_rule), OptionalNone {}); EXPECT_EQ(URL::PublicSuffixData::is_matching_public_suffix(*host, include_star_rule), test_case.is_public_suffix_with_star_rule); EXPECT_EQ(URL::PublicSuffixData::find_matching_public_suffix(*host, include_star_rule), test_case.host_public_suffix); EXPECT_EQ(URL::PublicSuffixData::find_matching_registrable_domain(*host, include_star_rule), test_case.host_registrable_domain); EXPECT_EQ(host->public_suffix(), test_case.host_public_suffix); EXPECT_EQ(host->registrable_domain(), test_case.host_registrable_domain); } } TEST_CASE(invalid_hosts) { StringView raw_invalid_inputs[] { " "sv, "/"sv, "com/"sv, "/com"sv, " com"sv, "com "sv, }; // Above inputs are not valid hosts, so should not be able to be parsed or matched in the PSL. for (auto const& input : raw_invalid_inputs) { auto exclude_star_rule = URL::PublicSuffixData::IncludeStarRule::No; auto host = URL::Parser::parse_host(input); EXPECT(!host.has_value()); EXPECT(!URL::PublicSuffixData::is_matching_public_suffix(input, exclude_star_rule)); EXPECT_EQ(URL::PublicSuffixData::find_matching_public_suffix(input, exclude_star_rule), OptionalNone {}); EXPECT_EQ(URL::PublicSuffixData::find_matching_registrable_domain(input, exclude_star_rule), OptionalNone {}); } } TEST_CASE(public_suffix_matching_for_ip_addresses) { StringView test_cases[] { "127.0.0.1"sv, "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"sv, }; for (auto const& input : test_cases) { auto exclude_star_rule = URL::PublicSuffixData::IncludeStarRule::No; EXPECT(!URL::PublicSuffixData::is_matching_public_suffix(input, exclude_star_rule)); EXPECT_EQ(URL::PublicSuffixData::find_matching_public_suffix(input, exclude_star_rule), OptionalNone {}); EXPECT_EQ(URL::PublicSuffixData::find_matching_registrable_domain(input, exclude_star_rule), OptionalNone {}); auto host = URL::Parser::parse_host(input); VERIFY(host.has_value()); EXPECT(!URL::PublicSuffixData::is_matching_public_suffix(*host, exclude_star_rule)); EXPECT_EQ(URL::PublicSuffixData::find_matching_public_suffix(*host, exclude_star_rule), OptionalNone {}); EXPECT_EQ(URL::PublicSuffixData::find_matching_registrable_domain(*host, exclude_star_rule), OptionalNone {}); EXPECT_EQ(host->public_suffix(), OptionalNone {}); EXPECT_EQ(host->registrable_domain(), OptionalNone {}); } }