Coverage Report

Created: 2025-08-08 06:27

/src/ada-url/fuzz/url_pattern.cc
Line
Count
Source (jump to first uncovered line)
1
#include <fuzzer/FuzzedDataProvider.h>
2
3
#include <memory>
4
#include <string>
5
6
#include "ada.cpp"
7
#include "ada.h"
8
9
using regex_provider = ada::url_pattern_regex::std_regex_provider;
10
11
780
std::string bytesToAlphanumeric(const std::string& source) {
12
780
  static const char alphanumeric[] =
13
780
      "abcdefghijklmnopqrstuvwxyz"
14
780
      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
15
780
      "0123456789";
16
17
780
  std::string result;
18
780
  result.reserve(source.size());
19
20
5.00k
  for (char byte : source) {
21
5.00k
    int index = static_cast<unsigned char>(byte) % (sizeof(alphanumeric) - 1);
22
5.00k
    result.push_back(alphanumeric[index]);
23
5.00k
  }
24
25
780
  return result;
26
780
}
27
28
585
void exercise_result(auto result) {
29
585
  (void)result.get_protocol();
30
585
  (void)result.get_username();
31
585
  (void)result.get_password();
32
585
  (void)result.get_hostname();
33
585
  (void)result.get_port();
34
585
  (void)result.get_pathname();
35
585
  (void)result.get_search();
36
585
  (void)result.get_hash();
37
585
  (void)result.ignore_case();
38
585
  (void)result.has_regexp_groups();
39
585
}
40
41
195
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
42
195
  FuzzedDataProvider fdp(data, size);
43
  // We do not want to trigger arbitrary regex matching.
44
195
  std::string source_1 =
45
195
      "/" + bytesToAlphanumeric(fdp.ConsumeRandomLengthString(50)) + "/" +
46
195
      bytesToAlphanumeric(fdp.ConsumeRandomLengthString(50));
47
195
  std::string base_source_1 =
48
195
      "/" + bytesToAlphanumeric(fdp.ConsumeRandomLengthString(50)) + "/" +
49
195
      bytesToAlphanumeric(fdp.ConsumeRandomLengthString(50));
50
51
195
  std::string source_2 = "https://ada-url.com/*";
52
195
  std::string base_source_2 = "https://ada-url.com";
53
54
195
  std::array<std::pair<std::string, std::string>, 2> sources = {{
55
195
      {source_1, base_source_1},
56
195
      {source_2, base_source_2},
57
195
  }};
58
59
390
  for (const auto& [source, base_source] : sources) {
60
    // Without base or options
61
390
    auto result =
62
390
        ada::parse_url_pattern<regex_provider>(source, nullptr, nullptr);
63
390
    if (result) exercise_result(*result);
64
65
    // Testing with base_url
66
390
    std::string_view base_source_view(base_source.data(), base_source.length());
67
390
    auto result_with_base = ada::parse_url_pattern<regex_provider>(
68
390
        source, &base_source_view, nullptr);
69
390
    if (result_with_base) exercise_result(*result_with_base);
70
71
    // Testing with base_url and options
72
390
    ada::url_pattern_options options{.ignore_case = fdp.ConsumeBool()};
73
390
    auto result_with_base_and_options = ada::parse_url_pattern<regex_provider>(
74
390
        source, &base_source_view, &options);
75
390
    if (result_with_base_and_options)
76
195
      exercise_result(*result_with_base_and_options);
77
78
    // Testing with url_pattern_init and base url.
79
390
    ada::url_pattern_init init{.protocol = source,
80
390
                               .username = source,
81
390
                               .password = source,
82
390
                               .hostname = source,
83
390
                               .port = source,
84
390
                               .pathname = source,
85
390
                               .search = source,
86
390
                               .hash = source};
87
390
    auto result_with_init = ada::parse_url_pattern<regex_provider>(
88
390
        init, &base_source_view, nullptr);
89
390
    if (result_with_init) exercise_result(*result_with_init);
90
390
  }
91
92
195
  return 0;
93
195
}