blob: 774a34a8e98c9dc7cd57f08d2c66615f05e3840a [file] [log] [blame]
Ben Kelly0e5c63e82020-11-12 21:24:081// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by an MIT-style license that can be
3// found in the LICENSE file or at https://opensource.org/licenses/MIT.
4
5#include "third_party/liburlpattern/parse.h"
6#include "testing/gtest/include/gtest/gtest.h"
7#include "third_party/liburlpattern/pattern.h"
8
9namespace liburlpattern {
10
11void RunParseTest(absl::string_view pattern,
12 absl::StatusOr<std::vector<Part>> expected) {
13 auto result = Parse(pattern);
14 ASSERT_EQ(result.ok(), expected.ok())
15 << "parse status '" << result.status() << "' for: " << pattern;
16 if (!expected.ok()) {
17 ASSERT_EQ(result.status().code(), expected.status().code())
18 << "parse status code for: " << pattern;
19 EXPECT_NE(result.status().message().find(expected.status().message()),
20 std::string::npos)
21 << "parse message '" << result.status().message()
22 << "' does not contain '" << expected.status().message()
23 << "' for: " << pattern;
24 return;
25 }
26 const auto& expected_part_list = expected.value();
27 const auto& part_list = result.value().PartList();
28 EXPECT_EQ(part_list.size(), expected_part_list.size())
29 << "parser should produce expected number of parts for: " << pattern;
30 for (size_t i = 0; i < part_list.size() && i < expected_part_list.size();
31 ++i) {
32 EXPECT_EQ(part_list[i], expected_part_list[i])
33 << "token at index " << i << " wrong for: " << pattern;
34 }
35}
36
37TEST(ParseTest, EmptyPattern) {
38 RunParseTest("", std::vector<Part>());
39}
40
41TEST(ParseTest, InvalidChar) {
42 RunParseTest("/foo/ßar", absl::InvalidArgumentError("Invalid character"));
43}
44
45TEST(ParseTest, Fixed) {
46 std::vector<Part> expected_parts = {
47 Part(PartType::kFixed, "/foo", Modifier::kNone),
48 };
49 RunParseTest("/foo", expected_parts);
50}
51
52TEST(ParseTest, FixedInGroup) {
53 std::vector<Part> expected_parts = {
54 Part(PartType::kFixed, "/foo", Modifier::kNone),
55 };
56 RunParseTest("{/foo}", expected_parts);
57}
58
59TEST(ParseTest, FixedAndEmptyGroup) {
60 std::vector<Part> expected_parts = {
61 Part(PartType::kFixed, "/f", Modifier::kNone),
62 Part(PartType::kFixed, "oo", Modifier::kNone),
63 };
64 RunParseTest("/f{}oo", expected_parts);
65}
66
67TEST(ParseTest, FixedInGroupWithOptionalModifier) {
68 std::vector<Part> expected_parts = {
69 Part(PartType::kFixed, "/foo", Modifier::kOptional),
70 };
71 RunParseTest("{/foo}?", expected_parts);
72}
73
74TEST(ParseTest, FixedInGroupWithZeroOrMoreModifier) {
75 std::vector<Part> expected_parts = {
76 Part(PartType::kFixed, "/foo", Modifier::kZeroOrMore),
77 };
78 RunParseTest("{/foo}*", expected_parts);
79}
80
81TEST(ParseTest, FixedInGroupWithOneOrMoreModifier) {
82 std::vector<Part> expected_parts = {
83 Part(PartType::kFixed, "/foo", Modifier::kOneOrMore),
84 };
85 RunParseTest("{/foo}+", expected_parts);
86}
87
88TEST(ParseTest, FixedInEarlyTerminatedGroup) {
89 RunParseTest("{/foo", absl::InvalidArgumentError("expected CLOSE"));
90}
91
92TEST(ParseTest, FixedInUnbalancedGroup) {
93 RunParseTest("{/foo?", absl::InvalidArgumentError("expected CLOSE"));
94}
95
96TEST(ParseTest, FixedWithModifier) {
Ben Kellyd228e3c2021-02-24 00:43:4097 RunParseTest("/foo?",
98 absl::InvalidArgumentError("Unexpected OTHER_MODIFIER"));
Ben Kelly0e5c63e82020-11-12 21:24:0899}
100
101TEST(ParseTest, Regex) {
102 std::vector<Part> expected_parts = {
103 Part(PartType::kFixed, "/f", Modifier::kNone),
104 Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"", "oo", /*suffix=*/"",
105 Modifier::kNone),
106 };
107 RunParseTest("/f(oo)", expected_parts);
108}
109
110TEST(ParseTest, RegexInGroup) {
111 std::vector<Part> expected_parts = {
112 Part(PartType::kFixed, "/f", Modifier::kNone),
113 Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"", "oo", /*suffix=*/"",
114 Modifier::kNone),
115 };
116 RunParseTest("/f{(oo)}", expected_parts);
117}
118
119TEST(ParseTest, RegexWithPrefixAndSuffixInGroup) {
120 std::vector<Part> expected_parts = {
121 Part(PartType::kFixed, "/", Modifier::kNone),
122 Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"f", "o", /*suffix=*/"o",
123 Modifier::kNone),
124 };
125 RunParseTest("/{f(o)o}", expected_parts);
126}
127
128TEST(ParseTest, RegexAndRegexInGroup) {
129 RunParseTest("/f{(o)(o)}", absl::InvalidArgumentError("expected CLOSE"));
130}
131
132TEST(ParseTest, RegexWithPrefix) {
133 std::vector<Part> expected_parts = {
134 Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"/", "foo", /*suffix=*/"",
135 Modifier::kNone),
136 };
137 RunParseTest("/(foo)", expected_parts);
138}
139
140TEST(ParseTest, RegexWithNameAndPrefix) {
141 std::vector<Part> expected_parts = {
142 Part(PartType::kFixed, "/foo", Modifier::kNone),
143 Part(PartType::kRegex, /*name=*/"bar", /*prefix=*/"/", "[^/]+?",
144 /*suffix=*/"", Modifier::kNone),
145 };
146 RunParseTest("/foo/:bar([^/]+?)", expected_parts);
147}
148
149TEST(ParseTest, RegexWithNameAndPrefixInGroup) {
150 std::vector<Part> expected_parts = {
151 Part(PartType::kFixed, "/foo/", Modifier::kNone),
152 Part(PartType::kRegex, /*name=*/"bar", /*prefix=*/"", "[^/]+?",
153 /*suffix=*/"", Modifier::kNone),
154 };
155 RunParseTest("/foo/{:bar([^/]+?)}", expected_parts);
156}
157
158TEST(ParseTest, RegexWithModifier) {
159 std::vector<Part> expected_parts = {
160 Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"/", "foo",
161 /*suffix=*/"", Modifier::kOptional),
162 };
163 RunParseTest("/(foo)?", expected_parts);
164}
165
166TEST(ParseTest, RegexLikeFullWildcard) {
167 std::vector<Part> expected_parts = {
Ben Kellyd228e3c2021-02-24 00:43:40168 Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"",
Ben Kelly0e5c63e82020-11-12 21:24:08169 /*suffix=*/"", Modifier::kNone),
170 };
171 RunParseTest("/(.*)", expected_parts);
172}
173
Ben Kellyd228e3c2021-02-24 00:43:40174TEST(ParseTest, Wildcard) {
175 std::vector<Part> expected_parts = {
176 Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"",
177 /*suffix=*/"", Modifier::kNone),
178 };
179 RunParseTest("/*", expected_parts);
180}
181
182TEST(ParseTest, WildcardWithModifierStar) {
183 std::vector<Part> expected_parts = {
184 Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"",
185 /*suffix=*/"", Modifier::kZeroOrMore),
186 };
187 RunParseTest("/**", expected_parts);
188}
189
190TEST(ParseTest, WildcardWithModifierPlus) {
191 std::vector<Part> expected_parts = {
192 Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"",
193 /*suffix=*/"", Modifier::kOneOrMore),
194 };
195 RunParseTest("/*+", expected_parts);
196}
197
198TEST(ParseTest, WildcardWithModifierQuestion) {
199 std::vector<Part> expected_parts = {
200 Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"",
201 /*suffix=*/"", Modifier::kOptional),
202 };
203 RunParseTest("/*?", expected_parts);
204}
205
206TEST(ParseTest, WildcardFollowingWildcardWithModifierStart) {
207 std::vector<Part> expected_parts = {
208 Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"",
209 /*suffix=*/"", Modifier::kZeroOrMore),
210 Part(PartType::kFullWildcard, /*name=*/"1", /*prefix=*/"", /*value=*/"",
211 /*suffix=*/"", Modifier::kNone),
212 };
213 RunParseTest("/***", expected_parts);
214}
215
216TEST(ParseTest, WildcardWithMultipleModifiersPlus) {
217 RunParseTest("/**+", absl::InvalidArgumentError("expected END"));
218}
219
220TEST(ParseTest, WildcardWithMultipleModifiersQuestion) {
221 RunParseTest("/**?", absl::InvalidArgumentError("expected END"));
222}
223
224TEST(ParseTest, WildcardInGroup) {
225 std::vector<Part> expected_parts = {
226 Part(PartType::kFixed, "/f", Modifier::kNone),
227 Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"", /*value=*/"",
228 /*suffix=*/"", Modifier::kNone),
229 };
230 RunParseTest("/f{*}", expected_parts);
231}
232
233TEST(ParseTest, WildcardWithPrefixAndSuffixInGroup) {
234 std::vector<Part> expected_parts = {
235 Part(PartType::kFixed, "/", Modifier::kNone),
236 Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"f", /*value=*/"",
237 /*suffix=*/"o", Modifier::kNone),
238 };
239 RunParseTest("/{f*o}", expected_parts);
240}
241
Ben Kelly0e5c63e82020-11-12 21:24:08242TEST(ParseTest, Name) {
243 std::vector<Part> expected_parts = {
244 Part(PartType::kFixed, "/foo", Modifier::kNone),
245 Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"",
246 /*value=*/"", /*suffix=*/"", Modifier::kNone),
247 };
248 RunParseTest("/foo:bar", expected_parts);
249}
250
251TEST(ParseTest, NameInGroup) {
252 std::vector<Part> expected_parts = {
253 Part(PartType::kFixed, "/foo", Modifier::kNone),
254 Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"",
255 /*value=*/"", /*suffix=*/"", Modifier::kNone),
256 };
257 RunParseTest("/foo{:bar}", expected_parts);
258}
259
260TEST(ParseTest, NameAndNameInGroup) {
261 RunParseTest("/foo{:bar:baz}", absl::InvalidArgumentError("expected CLOSE"));
262}
263
264TEST(ParseTest, NameWithPrefixAndSuffixInGroup) {
265 std::vector<Part> expected_parts = {
266 Part(PartType::kFixed, "/foo/", Modifier::kNone),
267 Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"data_",
268 /*value=*/"", /*suffix=*/".jpg", Modifier::kNone),
269 };
270 RunParseTest("/foo/{data_:bar.jpg}", expected_parts);
271}
272
273TEST(ParseTest, NameWithPrefix) {
274 std::vector<Part> expected_parts = {
275 Part(PartType::kFixed, "/foo", Modifier::kNone),
276 Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"/",
277 /*value=*/"", /*suffix=*/"", Modifier::kNone),
278 };
279 RunParseTest("/foo/:bar", expected_parts);
280}
281
282TEST(ParseTest, NameWithEscapedPrefix) {
283 std::vector<Part> expected_parts = {
284 Part(PartType::kFixed, "/foo/", Modifier::kNone),
285 Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"",
286 /*value=*/"", /*suffix=*/"", Modifier::kNone),
287 };
288 RunParseTest("/foo\\/:bar", expected_parts);
289}
290
291TEST(ParseTest, NameWithCustomRegex) {
292 std::vector<Part> expected_parts = {
293 Part(PartType::kFixed, "/foo", Modifier::kNone),
294 Part(PartType::kRegex, /*name=*/"bar", /*prefix=*/"", "[^/]+?",
295 /*suffix=*/"", Modifier::kNone),
296 };
297 RunParseTest("/foo:bar([^/]+?)", expected_parts);
298}
299
300TEST(ParseTest, NameWithModifier) {
301 std::vector<Part> expected_parts = {
302 Part(PartType::kSegmentWildcard, /*name=*/"foo", /*prefix=*/"/",
303 /*value=*/"", /*suffix=*/"", Modifier::kOptional),
304 };
305 RunParseTest("/:foo?", expected_parts);
306}
307
Ben Kellyd228e3c2021-02-24 00:43:40308TEST(ParseTest, NameWithModifierStarAndWildcard) {
309 std::vector<Part> expected_parts = {
310 Part(PartType::kSegmentWildcard, /*name=*/"foo", /*prefix=*/"/",
311 /*value=*/"", /*suffix=*/"", Modifier::kZeroOrMore),
312 Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"",
313 /*value=*/"", /*suffix=*/"", Modifier::kNone),
314 };
315 RunParseTest("/:foo**", expected_parts);
316}
317
318TEST(ParseTest, NameWithModifierStarAndModifierQuestion) {
319 RunParseTest("/:foo*?", absl::InvalidArgumentError("expected END"));
320}
321
322TEST(ParseTest, NameWithModifierStarAndModifierPlus) {
323 RunParseTest("/:foo*+", absl::InvalidArgumentError("expected END"));
324}
325
Ben Kelly0e5c63e82020-11-12 21:24:08326} // namespace liburlpattern