diff --git a/fuzz/url_pattern.cc b/fuzz/url_pattern.cc index f7c9da3e6..f3f1bfcd7 100644 --- a/fuzz/url_pattern.cc +++ b/fuzz/url_pattern.cc @@ -6,6 +6,8 @@ #include "ada.cpp" #include "ada.h" +using regex_provider = ada::url_pattern_regex::std_regex_provider; + std::string bytesToAlphanumeric(const std::string& source) { static const char alphanumeric[] = "abcdefghijklmnopqrstuvwxyz" @@ -34,19 +36,20 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { bytesToAlphanumeric(fdp.ConsumeRandomLengthString(50)); // Without base or options - auto result = ada::parse_url_pattern(source, nullptr, nullptr); + auto result = + ada::parse_url_pattern(source, nullptr, nullptr); (void)result; // Testing with base_url std::string_view base_source_view(base_source.data(), base_source.length()); - auto result_with_base = - ada::parse_url_pattern(source, &base_source_view, nullptr); + auto result_with_base = ada::parse_url_pattern( + source, &base_source_view, nullptr); (void)result_with_base; // Testing with base_url and options ada::url_pattern_options options{.ignore_case = true}; - auto result_with_base_and_options = - ada::parse_url_pattern(source, &base_source_view, &options); + auto result_with_base_and_options = ada::parse_url_pattern( + source, &base_source_view, &options); (void)result_with_base_and_options; // Testing with url_pattern_init and base url. @@ -59,7 +62,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { .search = source, .hash = source}; auto result_with_init = - ada::parse_url_pattern(init, &base_source_view, nullptr); + ada::parse_url_pattern(init, &base_source_view, nullptr); (void)result_with_init; return 0; diff --git a/include/ada/implementation.h b/include/ada/implementation.h index e79670031..0f07e4f2c 100644 --- a/include/ada/implementation.h +++ b/include/ada/implementation.h @@ -55,8 +55,7 @@ bool can_parse(std::string_view input, * @param options an optional url_pattern_options struct * @return url_pattern instance */ -template +template ada_warn_unused tl::expected, errors> parse_url_pattern(std::variant input, const std::string_view* base_url = nullptr, diff --git a/include/ada/parser-inl.h b/include/ada/parser-inl.h index ece16a0e5..92378c58e 100644 --- a/include/ada/parser-inl.h +++ b/include/ada/parser-inl.h @@ -267,11 +267,6 @@ tl::expected, errors> parse_url_pattern_impl( return url_pattern_; } -template tl::expected, - errors> -parse_url_pattern_impl(std::variant input, - const std::string_view* base_url, - const url_pattern_options* options); } // namespace ada::parser #endif // ADA_PARSER_INL_H diff --git a/include/ada/parser.h b/include/ada/parser.h index ad2ec58cf..92bed4560 100644 --- a/include/ada/parser.h +++ b/include/ada/parser.h @@ -58,12 +58,6 @@ tl::expected, errors> parse_url_pattern_impl( std::variant input, const std::string_view* base_url, const url_pattern_options* options); -extern template tl::expected, - errors> -parse_url_pattern_impl(std::variant input, - const std::string_view* base_url, - const url_pattern_options* options); - } // namespace ada::parser #endif // ADA_PARSER_H diff --git a/include/ada/url_pattern-inl.h b/include/ada/url_pattern-inl.h index d12ed55e4..b819ba8c9 100644 --- a/include/ada/url_pattern-inl.h +++ b/include/ada/url_pattern-inl.h @@ -25,17 +25,6 @@ inline bool url_pattern_component_result::operator==( return input == other.input && groups == other.groups; } -template -std::string url_pattern_component::to_string() const { -#ifdef ADA_HAS_FORMAT - return std::format(R"({{"pattern": "{}", "has_regexp_groups": {}}})", pattern, - has_regexp_groups ? "true" : "false" //, - ); -#else - return ""; -#endif -} - template url_pattern_component_result url_pattern_component::create_component_match_result( @@ -62,21 +51,6 @@ url_pattern_component::create_component_match_result( return result; } -template -std::string url_pattern::to_string() const { -#ifdef ADA_HAS_FORMAT - return std::format( - R"({{"protocol_component": "{}", "username_component": {}, "password_component": {}, "hostname_component": {}, "port_component": {}, "pathname_component": {}, "search_component": {}, "hash_component": {}, "ignore_case": {}}})", - protocol_component.to_string(), username_component.to_string(), - password_component.to_string(), hostname_component.to_string(), - port_component.to_string(), pathname_component.to_string(), - search_component.to_string(), hash_component.to_string(), - ignore_case_ ? "true" : "false"); -#else - return ""; -#endif -} - template std::string_view url_pattern::get_protocol() const ada_lifetime_bound { diff --git a/include/ada/url_pattern.h b/include/ada/url_pattern.h index 241136ecd..0cfe46c6f 100644 --- a/include/ada/url_pattern.h +++ b/include/ada/url_pattern.h @@ -176,7 +176,17 @@ class url_pattern_component { std::string_view input, std::vector>&& exec_result); - std::string to_string() const; +#if ADA_TESTING + friend void PrintTo(const url_pattern_component& component, + std::ostream* os) { + *os << "pattern: '" << component.pattern + << "', has_regexp_groups: " << component.has_regexp_groups + << "group_name_list: "; + for (const auto& name : component.group_name_list) { + *os << name << ", "; + } + } +#endif // ADA_TESTING typename regex_provider::regex_type regexp{}; std::string pattern{}; @@ -204,7 +214,11 @@ struct url_pattern_result { struct url_pattern_options { bool ignore_case = false; - std::string to_string() const; +#if ADA_TESTING + friend void PrintTo(const url_pattern_options& options, std::ostream* os) { + *os << "ignore_case: '" << options.ignore_case; + } +#endif // ADA_TESTING }; // URLPattern is a Web Platform standard API for matching URLs against a @@ -259,7 +273,18 @@ class url_pattern { // @see https://urlpattern.spec.whatwg.org/#url-pattern-has-regexp-groups [[nodiscard]] bool has_regexp_groups() const; - [[nodiscard]] std::string to_string() const; +#if ADA_TESTING + friend void PrintTo(const url_pattern& c, std::ostream* os) { + *os << "protocol_component: '" << c.get_protocol() << ", "; + *os << "username_component: '" << c.get_username() << ", "; + *os << "password_component: '" << c.get_password() << ", "; + *os << "hostname_component: '" << c.get_hostname() << ", "; + *os << "port_component: '" << c.get_port() << ", "; + *os << "pathname_component: '" << c.get_pathname() << ", "; + *os << "search_component: '" << c.get_search() << ", "; + *os << "hash_component: '" << c.get_hash(); + } +#endif // ADA_TESTING url_pattern_component protocol_component{}; url_pattern_component username_component{}; diff --git a/include/ada/url_pattern_init.h b/include/ada/url_pattern_init.h index a815ec8bc..b4f55e6e5 100644 --- a/include/ada/url_pattern_init.h +++ b/include/ada/url_pattern_init.h @@ -11,6 +11,10 @@ #include #include +#if ADA_TESTING +#include +#endif // ADA_TESTING + namespace ada { // Important: C++20 allows us to use concept rather than `using` or `typedef @@ -72,7 +76,19 @@ struct url_pattern_init { static tl::expected process_hash(std::string_view value, std::string_view type); - [[nodiscard]] std::string to_string() const; +#if ADA_TESTING + friend void PrintTo(const url_pattern_init& init, std::ostream* os) { + *os << "protocol: '" << init.protocol.value_or("undefined") << "', "; + *os << "username: '" << init.username.value_or("undefined") << "', "; + *os << "password: '" << init.password.value_or("undefined") << "', "; + *os << "hostname: '" << init.hostname.value_or("undefined") << "', "; + *os << "port: '" << init.port.value_or("undefined") << "', "; + *os << "pathname: '" << init.pathname.value_or("undefined") << "', "; + *os << "search: '" << init.search.value_or("undefined") << "', "; + *os << "hash: '" << init.hash.value_or("undefined") << "', "; + *os << "base_url: '" << init.base_url.value_or("undefined") << "', "; + } +#endif // ADA_TESTING bool operator==(const url_pattern_init&) const; diff --git a/src/url_pattern.cpp b/src/url_pattern.cpp index 1ffbfda02..8ef7dc15b 100644 --- a/src/url_pattern.cpp +++ b/src/url_pattern.cpp @@ -362,77 +362,4 @@ tl::expected url_pattern_init::process_hash( return url_pattern_helpers::canonicalize_hash(value); } -std::string url_pattern_options::to_string() const { - std::string answer; - answer.append("{\n"); - answer.append("\t\"ignore_case\":\""); - answer.append(ignore_case ? "true" : "false"); - answer.append("\",\n"); - answer.append("}"); - return answer; -} - -std::string url_pattern_init::to_string() const { - std::string answer; - auto back = std::back_insert_iterator(answer); - answer.append("{\n"); - - if (protocol.has_value()) { - answer.append("\t\"protocol\":\""); - helpers::encode_json(protocol.value(), back); - answer.append("\",\n"); - } - - if (username.has_value()) { - answer.append("\t\"username\":\""); - helpers::encode_json(username.value(), back); - answer.append("\",\n"); - } - - if (password.has_value()) { - answer.append("\t\"password\":\""); - helpers::encode_json(password.value(), back); - answer.append("\",\n"); - } - - if (hostname.has_value()) { - answer.append("\t\"hostname\":\""); - helpers::encode_json(hostname.value(), back); - answer.append("\",\n"); - } - - if (port.has_value()) { - answer.append("\t\"port\":\""); - helpers::encode_json(port.value(), back); - answer.append("\",\n"); - } - - if (pathname.has_value()) { - answer.append("\t\"pathname\":\""); - helpers::encode_json(pathname.value(), back); - answer.append("\",\n"); - } - - if (search.has_value()) { - answer.append("\t\"search\":\""); - helpers::encode_json(search.value(), back); - answer.append("\",\n"); - } - - if (hash.has_value()) { - answer.append("\t\"hash\":\""); - helpers::encode_json(hash.value(), back); - answer.append("\",\n"); - } - - if (base_url.has_value()) { - answer.append("\t\"base_url\":\""); - helpers::encode_json(base_url.value(), back); - answer.append("\",\n"); - } - - answer.append("}"); - return answer; -} - } // namespace ada diff --git a/tests/wpt_urlpattern_tests.cpp b/tests/wpt_urlpattern_tests.cpp index 93b694aee..e01094722 100644 --- a/tests/wpt_urlpattern_tests.cpp +++ b/tests/wpt_urlpattern_tests.cpp @@ -10,6 +10,7 @@ #include "ada/parser.h" using namespace simdjson; +using regex_provider = ada::url_pattern_regex::std_regex_provider; constexpr std::string_view URL_PATTERN_TEST_DATA = "wpt/urlpatterntestdata.json"; @@ -94,31 +95,36 @@ TEST(wpt_urlpattern_tests, has_regexp_groups) { for (const auto& field : fields) { std::cout << "field " << field << std::endl; - ASSERT_FALSE( - ada::parse_url_pattern(create_init(field, "*"))->has_regexp_groups()); - ASSERT_FALSE(ada::parse_url_pattern(create_init(field, ":foo")) - ->has_regexp_groups()); - ASSERT_FALSE(ada::parse_url_pattern(create_init(field, ":foo?")) + ASSERT_FALSE(ada::parse_url_pattern(create_init(field, "*")) ->has_regexp_groups()); - ASSERT_TRUE(ada::parse_url_pattern(create_init(field, ":foo(hi)")) - ->has_regexp_groups()); - ASSERT_TRUE(ada::parse_url_pattern(create_init(field, "(hi)")) - ->has_regexp_groups()); + ASSERT_FALSE( + ada::parse_url_pattern(create_init(field, ":foo")) + ->has_regexp_groups()); + ASSERT_FALSE( + ada::parse_url_pattern(create_init(field, ":foo?")) + ->has_regexp_groups()); + ASSERT_TRUE( + ada::parse_url_pattern(create_init(field, ":foo(hi)")) + ->has_regexp_groups()); + ASSERT_TRUE( + ada::parse_url_pattern(create_init(field, "(hi)")) + ->has_regexp_groups()); if (field != "protocol" && field != "port") { - ASSERT_FALSE( - ada::parse_url_pattern(create_init(field, "a-{:hello}-z-*-a")) - ->has_regexp_groups()); - ASSERT_TRUE(ada::parse_url_pattern(create_init(field, "a-(hi)-z-(lo)-a")) + ASSERT_FALSE(ada::parse_url_pattern( + create_init(field, "a-{:hello}-z-*-a")) + ->has_regexp_groups()); + ASSERT_TRUE(ada::parse_url_pattern( + create_init(field, "a-(hi)-z-(lo)-a")) ->has_regexp_groups()); } } - ASSERT_FALSE(ada::parse_url_pattern( + ASSERT_FALSE(ada::parse_url_pattern( ada::url_pattern_init{.pathname = "/a/:foo/:baz?/b/*"}) ->has_regexp_groups()); ASSERT_TRUE( - ada::parse_url_pattern( + ada::parse_url_pattern( ada::url_pattern_init{.pathname = "/a/:foo/:baz([a-z]+)?/b/*"}) ->has_regexp_groups()); @@ -259,15 +265,14 @@ parse_pattern( if (std::holds_alternative(init_variant)) { auto str_init = std::get(init_variant); std::cout << "init: " << str_init << std::endl; - return ada::parse_url_pattern( + return ada::parse_url_pattern( std::string_view(str_init), base_url.has_value() ? &base_url_view : nullptr, options.has_value() ? &options.value() : nullptr); } auto obj_init = std::get(init_variant); - std::cout << "init: " << obj_init.to_string() << std::endl; - return ada::parse_url_pattern( + return ada::parse_url_pattern( obj_init, base_url.has_value() ? &base_url_view : nullptr, options.has_value() ? &options.value() : nullptr); } @@ -443,9 +448,6 @@ TEST(wpt_urlpattern_tests, urlpattern_test_data) { if (base_url) { std::cerr << "base_url: " << base_url.value_or("") << std::endl; } - if (options) { - std::cerr << "options: " << options->to_string() << std::endl; - } FAIL() << "Test should have succeeded but failed" << std::endl << main_object.raw_json().value() << std::endl; }