/src/ada-url/fuzz/can_parse.cc
Line | Count | Source |
1 | | #include <fuzzer/FuzzedDataProvider.h> |
2 | | |
3 | | #include <cstdio> |
4 | | #include <memory> |
5 | | #include <string> |
6 | | |
7 | | #include "ada.cpp" |
8 | | #include "ada.h" |
9 | | |
10 | 7.06k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
11 | 7.06k | FuzzedDataProvider fdp(data, size); |
12 | 7.06k | std::string source = fdp.ConsumeRandomLengthString(256); |
13 | 7.06k | std::string base_source = fdp.ConsumeRandomLengthString(256); |
14 | | |
15 | | /** |
16 | | * ada::can_parse consistency checks. |
17 | | * |
18 | | * can_parse() must agree with parse().has_value() in all cases. |
19 | | * This invariant must hold regardless of input encoding. |
20 | | */ |
21 | | |
22 | | // Test 1: can_parse(source) must equal |
23 | | // parse<url_aggregator>(source).has_value() |
24 | 7.06k | bool can_parse_result = ada::can_parse(source); |
25 | 7.06k | auto parsed_agg = ada::parse<ada::url_aggregator>(source); |
26 | 7.06k | if (can_parse_result != parsed_agg.has_value()) { |
27 | 0 | printf("can_parse vs parse<url_aggregator> inconsistency for: %s\n", |
28 | 0 | source.c_str()); |
29 | 0 | abort(); |
30 | 0 | } |
31 | | |
32 | | // Test 2: can_parse(source) must also equal parse<url>(source).has_value() |
33 | 7.06k | auto parsed_url = ada::parse<ada::url>(source); |
34 | 7.06k | if (can_parse_result != parsed_url.has_value()) { |
35 | 0 | printf("can_parse vs parse<url> inconsistency for: %s\n", source.c_str()); |
36 | 0 | abort(); |
37 | 0 | } |
38 | | |
39 | | // Test 3: can_parse with base |
40 | 7.06k | auto base_source_view = |
41 | 7.06k | std::string_view(base_source.data(), base_source.length()); |
42 | 7.06k | bool can_parse_with_base = ada::can_parse(source, &base_source_view); |
43 | | |
44 | | // Test 4: can_parse(source, base) must equal parse<url_aggregator>(source, |
45 | | // base).has_value() |
46 | 7.06k | auto base_agg = ada::parse<ada::url_aggregator>(base_source); |
47 | 7.06k | if (base_agg) { |
48 | 2.46k | auto parsed_with_base = ada::parse<ada::url_aggregator>(source, &*base_agg); |
49 | 2.46k | if (can_parse_with_base != parsed_with_base.has_value()) { |
50 | 0 | printf( |
51 | 0 | "can_parse_with_base vs parse<url_aggregator> inconsistency for " |
52 | 0 | "source=%s base=%s\n", |
53 | 0 | source.c_str(), base_source.c_str()); |
54 | 0 | abort(); |
55 | 0 | } |
56 | 2.46k | } |
57 | | |
58 | | // Test 5: Empty string edge cases |
59 | 7.06k | { |
60 | 7.06k | std::string_view empty_view; |
61 | 7.06k | bool empty_can_parse = ada::can_parse(""); |
62 | 7.06k | auto empty_parsed = ada::parse<ada::url_aggregator>(""); |
63 | 7.06k | if (empty_can_parse != empty_parsed.has_value()) { |
64 | 0 | printf("Empty string can_parse inconsistency\n"); |
65 | 0 | abort(); |
66 | 0 | } |
67 | 7.06k | } |
68 | | |
69 | | // Test 6: href round-trip. |
70 | | // |
71 | | // If parse(source) succeeds, can_parse(href) must return true and |
72 | | // re-parsing the href must produce the same href (idempotency). |
73 | | // This verifies that the serialised form of every parsed URL is itself |
74 | | // a valid absolute URL that round-trips perfectly. |
75 | 7.06k | if (parsed_agg) { |
76 | 3.26k | std::string href = std::string(parsed_agg->get_href()); |
77 | | |
78 | | // can_parse must accept the normalised href. |
79 | 3.26k | if (!ada::can_parse(href)) { |
80 | 0 | printf("can_parse rejected normalised href: '%s'\n", href.c_str()); |
81 | 0 | abort(); |
82 | 0 | } |
83 | | |
84 | | // Re-parsing the href must succeed. |
85 | 3.26k | auto reparsed = ada::parse<ada::url_aggregator>(href); |
86 | 3.26k | if (!reparsed) { |
87 | 0 | printf("Re-parse of href failed: '%s'\n", href.c_str()); |
88 | 0 | abort(); |
89 | 0 | } |
90 | | |
91 | | // The href of the re-parsed URL must equal the original href. |
92 | 3.26k | std::string href2 = std::string(reparsed->get_href()); |
93 | 3.26k | if (href2 != href) { |
94 | 0 | printf( |
95 | 0 | "href idempotency failure!\n" |
96 | 0 | " href1: %s\n href2: %s\n", |
97 | 0 | href.c_str(), href2.c_str()); |
98 | 0 | abort(); |
99 | 0 | } |
100 | | |
101 | | // url and url_aggregator must agree on whether the href is parseable. |
102 | 3.26k | bool url_can_parse = ada::parse<ada::url>(href).has_value(); |
103 | 3.26k | if (url_can_parse != ada::can_parse(href)) { |
104 | 0 | printf("parse<url> vs can_parse disagreement on normalised href: '%s'\n", |
105 | 0 | href.c_str()); |
106 | 0 | abort(); |
107 | 0 | } |
108 | 3.26k | } |
109 | | |
110 | 7.06k | (void)can_parse_result; |
111 | 7.06k | (void)can_parse_with_base; |
112 | | |
113 | 7.06k | return 0; |
114 | 7.06k | } |