Avi Drissman | 505076bc | 2022-10-06 21:15:30 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 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" |
Helmut Januschka | ed56d61 | 2024-07-12 21:11:09 | [diff] [blame] | 6 | |
| 7 | #include <string_view> |
| 8 | |
Takashi Nakayama | e011ac4 | 2025-05-02 00:20:01 | [diff] [blame] | 9 | #include "base/types/expected.h" |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 10 | #include "testing/gtest/include/gtest/gtest.h" |
Takashi Nakayama | e011ac4 | 2025-05-02 00:20:01 | [diff] [blame] | 11 | #include "third_party/abseil-cpp/absl/status/status.h" |
| 12 | #include "third_party/abseil-cpp/absl/status/statusor.h" |
Ben Kelly | d18c0e82 | 2021-03-05 22:42:17 | [diff] [blame] | 13 | #include "third_party/abseil-cpp/absl/strings/str_format.h" |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 14 | #include "third_party/liburlpattern/pattern.h" |
| 15 | |
Ben Kelly | 02c1d17 | 2021-03-16 15:33:25 | [diff] [blame] | 16 | namespace { |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 17 | |
Takashi Nakayama | e011ac4 | 2025-05-02 00:20:01 | [diff] [blame] | 18 | base::expected<std::string, absl::Status> PassThrough(std::string_view input) { |
Ben Kelly | d18c0e82 | 2021-03-05 22:42:17 | [diff] [blame] | 19 | return std::string(input); |
| 20 | } |
| 21 | |
Ben Kelly | 02c1d17 | 2021-03-16 15:33:25 | [diff] [blame] | 22 | } // namespace |
| 23 | |
| 24 | namespace liburlpattern { |
| 25 | |
Takashi Nakayama | e011ac4 | 2025-05-02 00:20:01 | [diff] [blame] | 26 | base::expected<std::string, absl::Status> ToUpper(std::string_view input) { |
Ben Kelly | d18c0e82 | 2021-03-05 22:42:17 | [diff] [blame] | 27 | std::string output; |
| 28 | std::transform(input.begin(), input.end(), std::back_inserter(output), |
| 29 | [](unsigned char c) { return std::toupper(c); }); |
| 30 | return output; |
| 31 | } |
| 32 | |
Helmut Januschka | ed56d61 | 2024-07-12 21:11:09 | [diff] [blame] | 33 | void RunParseTest(std::string_view pattern, |
Ben Kelly | d18c0e82 | 2021-03-05 22:42:17 | [diff] [blame] | 34 | absl::StatusOr<std::vector<Part>> expected, |
| 35 | EncodeCallback callback = PassThrough) { |
| 36 | auto result = Parse(pattern, std::move(callback)); |
Takashi Nakayama | e011ac4 | 2025-05-02 00:20:01 | [diff] [blame] | 37 | ASSERT_EQ(result.has_value(), expected.ok()) |
| 38 | << "parse status '" << result.error() << "' for: " << pattern; |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 39 | if (!expected.ok()) { |
Takashi Nakayama | e011ac4 | 2025-05-02 00:20:01 | [diff] [blame] | 40 | ASSERT_EQ(result.error().code(), expected.status().code()) |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 41 | << "parse status code for: " << pattern; |
Takashi Nakayama | e011ac4 | 2025-05-02 00:20:01 | [diff] [blame] | 42 | EXPECT_NE(result.error().message().find(expected.status().message()), |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 43 | std::string::npos) |
Takashi Nakayama | e011ac4 | 2025-05-02 00:20:01 | [diff] [blame] | 44 | << "parse message '" << result.error().message() |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 45 | << "' does not contain '" << expected.status().message() |
| 46 | << "' for: " << pattern; |
| 47 | return; |
| 48 | } |
| 49 | const auto& expected_part_list = expected.value(); |
| 50 | const auto& part_list = result.value().PartList(); |
| 51 | EXPECT_EQ(part_list.size(), expected_part_list.size()) |
| 52 | << "parser should produce expected number of parts for: " << pattern; |
| 53 | for (size_t i = 0; i < part_list.size() && i < expected_part_list.size(); |
| 54 | ++i) { |
| 55 | EXPECT_EQ(part_list[i], expected_part_list[i]) |
| 56 | << "token at index " << i << " wrong for: " << pattern; |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | TEST(ParseTest, EmptyPattern) { |
| 61 | RunParseTest("", std::vector<Part>()); |
| 62 | } |
| 63 | |
Ben Kelly | d18c0e82 | 2021-03-05 22:42:17 | [diff] [blame] | 64 | TEST(ParseTest, EncoderCallback) { |
| 65 | std::vector<Part> expected_parts = { |
| 66 | Part(PartType::kFixed, "/FOO/BAR", Modifier::kNone), |
| 67 | }; |
| 68 | RunParseTest("/foo/bar", expected_parts, ToUpper); |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | TEST(ParseTest, Fixed) { |
| 72 | std::vector<Part> expected_parts = { |
| 73 | Part(PartType::kFixed, "/foo", Modifier::kNone), |
| 74 | }; |
| 75 | RunParseTest("/foo", expected_parts); |
| 76 | } |
| 77 | |
| 78 | TEST(ParseTest, FixedInGroup) { |
| 79 | std::vector<Part> expected_parts = { |
| 80 | Part(PartType::kFixed, "/foo", Modifier::kNone), |
| 81 | }; |
| 82 | RunParseTest("{/foo}", expected_parts); |
| 83 | } |
| 84 | |
Ben Kelly | ccecd87 | 2021-07-27 18:37:17 | [diff] [blame] | 85 | TEST(ParseTest, FixedAndFixedInGroup) { |
| 86 | std::vector<Part> expected_parts = { |
| 87 | Part(PartType::kFixed, "/foo", Modifier::kNone), |
| 88 | }; |
| 89 | RunParseTest("/{foo}", expected_parts); |
| 90 | } |
| 91 | |
| 92 | TEST(ParseTest, FixedInGroupAndFixed) { |
| 93 | std::vector<Part> expected_parts = { |
| 94 | Part(PartType::kFixed, "/foo", Modifier::kNone), |
| 95 | }; |
| 96 | RunParseTest("{/}foo", expected_parts); |
| 97 | } |
| 98 | |
| 99 | TEST(ParseTest, FixedInGroupAndFixedInGroup) { |
| 100 | std::vector<Part> expected_parts = { |
| 101 | Part(PartType::kFixed, "/foo", Modifier::kNone), |
| 102 | }; |
| 103 | RunParseTest("{/}{foo}", expected_parts); |
| 104 | } |
| 105 | |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 106 | TEST(ParseTest, FixedAndEmptyGroup) { |
| 107 | std::vector<Part> expected_parts = { |
Ben Kelly | ccecd87 | 2021-07-27 18:37:17 | [diff] [blame] | 108 | Part(PartType::kFixed, "/foo", Modifier::kNone), |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 109 | }; |
| 110 | RunParseTest("/f{}oo", expected_parts); |
| 111 | } |
| 112 | |
| 113 | TEST(ParseTest, FixedInGroupWithOptionalModifier) { |
| 114 | std::vector<Part> expected_parts = { |
| 115 | Part(PartType::kFixed, "/foo", Modifier::kOptional), |
| 116 | }; |
| 117 | RunParseTest("{/foo}?", expected_parts); |
| 118 | } |
| 119 | |
| 120 | TEST(ParseTest, FixedInGroupWithZeroOrMoreModifier) { |
| 121 | std::vector<Part> expected_parts = { |
| 122 | Part(PartType::kFixed, "/foo", Modifier::kZeroOrMore), |
| 123 | }; |
| 124 | RunParseTest("{/foo}*", expected_parts); |
| 125 | } |
| 126 | |
| 127 | TEST(ParseTest, FixedInGroupWithOneOrMoreModifier) { |
| 128 | std::vector<Part> expected_parts = { |
| 129 | Part(PartType::kFixed, "/foo", Modifier::kOneOrMore), |
| 130 | }; |
| 131 | RunParseTest("{/foo}+", expected_parts); |
| 132 | } |
| 133 | |
| 134 | TEST(ParseTest, FixedInEarlyTerminatedGroup) { |
Ben Kelly | 18869af75 | 2021-07-14 02:08:25 | [diff] [blame] | 135 | RunParseTest("{/foo", absl::InvalidArgumentError("expected '}'")); |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 136 | } |
| 137 | |
| 138 | TEST(ParseTest, FixedInUnbalancedGroup) { |
Ben Kelly | 18869af75 | 2021-07-14 02:08:25 | [diff] [blame] | 139 | RunParseTest("{/foo?", absl::InvalidArgumentError("expected '}'")); |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | TEST(ParseTest, FixedWithModifier) { |
Ben Kelly | 18869af75 | 2021-07-14 02:08:25 | [diff] [blame] | 143 | RunParseTest("/foo?", absl::InvalidArgumentError("Unexpected modifier")); |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 144 | } |
| 145 | |
| 146 | TEST(ParseTest, Regex) { |
| 147 | std::vector<Part> expected_parts = { |
| 148 | Part(PartType::kFixed, "/f", Modifier::kNone), |
| 149 | Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"", "oo", /*suffix=*/"", |
| 150 | Modifier::kNone), |
| 151 | }; |
| 152 | RunParseTest("/f(oo)", expected_parts); |
| 153 | } |
| 154 | |
| 155 | TEST(ParseTest, RegexInGroup) { |
| 156 | std::vector<Part> expected_parts = { |
| 157 | Part(PartType::kFixed, "/f", Modifier::kNone), |
| 158 | Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"", "oo", /*suffix=*/"", |
| 159 | Modifier::kNone), |
| 160 | }; |
| 161 | RunParseTest("/f{(oo)}", expected_parts); |
| 162 | } |
| 163 | |
| 164 | TEST(ParseTest, RegexWithPrefixAndSuffixInGroup) { |
| 165 | std::vector<Part> expected_parts = { |
| 166 | Part(PartType::kFixed, "/", Modifier::kNone), |
| 167 | Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"f", "o", /*suffix=*/"o", |
| 168 | Modifier::kNone), |
| 169 | }; |
| 170 | RunParseTest("/{f(o)o}", expected_parts); |
| 171 | } |
| 172 | |
| 173 | TEST(ParseTest, RegexAndRegexInGroup) { |
Ben Kelly | 18869af75 | 2021-07-14 02:08:25 | [diff] [blame] | 174 | RunParseTest("/f{(o)(o)}", absl::InvalidArgumentError("expected '}'")); |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 175 | } |
| 176 | |
| 177 | TEST(ParseTest, RegexWithPrefix) { |
| 178 | std::vector<Part> expected_parts = { |
| 179 | Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"/", "foo", /*suffix=*/"", |
| 180 | Modifier::kNone), |
| 181 | }; |
| 182 | RunParseTest("/(foo)", expected_parts); |
| 183 | } |
| 184 | |
| 185 | TEST(ParseTest, RegexWithNameAndPrefix) { |
| 186 | std::vector<Part> expected_parts = { |
| 187 | Part(PartType::kFixed, "/foo", Modifier::kNone), |
| 188 | Part(PartType::kRegex, /*name=*/"bar", /*prefix=*/"/", "[^/]+?", |
| 189 | /*suffix=*/"", Modifier::kNone), |
| 190 | }; |
| 191 | RunParseTest("/foo/:bar([^/]+?)", expected_parts); |
| 192 | } |
| 193 | |
| 194 | TEST(ParseTest, RegexWithNameAndPrefixInGroup) { |
| 195 | std::vector<Part> expected_parts = { |
| 196 | Part(PartType::kFixed, "/foo/", Modifier::kNone), |
| 197 | Part(PartType::kRegex, /*name=*/"bar", /*prefix=*/"", "[^/]+?", |
| 198 | /*suffix=*/"", Modifier::kNone), |
| 199 | }; |
| 200 | RunParseTest("/foo/{:bar([^/]+?)}", expected_parts); |
| 201 | } |
| 202 | |
| 203 | TEST(ParseTest, RegexWithModifier) { |
| 204 | std::vector<Part> expected_parts = { |
| 205 | Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"/", "foo", |
| 206 | /*suffix=*/"", Modifier::kOptional), |
| 207 | }; |
| 208 | RunParseTest("/(foo)?", expected_parts); |
| 209 | } |
| 210 | |
| 211 | TEST(ParseTest, RegexLikeFullWildcard) { |
| 212 | std::vector<Part> expected_parts = { |
Ben Kelly | d228e3c | 2021-02-24 00:43:40 | [diff] [blame] | 213 | Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"", |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 214 | /*suffix=*/"", Modifier::kNone), |
| 215 | }; |
| 216 | RunParseTest("/(.*)", expected_parts); |
| 217 | } |
| 218 | |
Ben Kelly | d228e3c | 2021-02-24 00:43:40 | [diff] [blame] | 219 | TEST(ParseTest, Wildcard) { |
| 220 | std::vector<Part> expected_parts = { |
| 221 | Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"", |
| 222 | /*suffix=*/"", Modifier::kNone), |
| 223 | }; |
| 224 | RunParseTest("/*", expected_parts); |
| 225 | } |
| 226 | |
| 227 | TEST(ParseTest, WildcardWithModifierStar) { |
| 228 | std::vector<Part> expected_parts = { |
| 229 | Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"", |
| 230 | /*suffix=*/"", Modifier::kZeroOrMore), |
| 231 | }; |
| 232 | RunParseTest("/**", expected_parts); |
| 233 | } |
| 234 | |
| 235 | TEST(ParseTest, WildcardWithModifierPlus) { |
| 236 | std::vector<Part> expected_parts = { |
| 237 | Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"", |
| 238 | /*suffix=*/"", Modifier::kOneOrMore), |
| 239 | }; |
| 240 | RunParseTest("/*+", expected_parts); |
| 241 | } |
| 242 | |
| 243 | TEST(ParseTest, WildcardWithModifierQuestion) { |
| 244 | std::vector<Part> expected_parts = { |
| 245 | Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"", |
| 246 | /*suffix=*/"", Modifier::kOptional), |
| 247 | }; |
| 248 | RunParseTest("/*?", expected_parts); |
| 249 | } |
| 250 | |
| 251 | TEST(ParseTest, WildcardFollowingWildcardWithModifierStart) { |
| 252 | std::vector<Part> expected_parts = { |
| 253 | Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"", |
| 254 | /*suffix=*/"", Modifier::kZeroOrMore), |
| 255 | Part(PartType::kFullWildcard, /*name=*/"1", /*prefix=*/"", /*value=*/"", |
| 256 | /*suffix=*/"", Modifier::kNone), |
| 257 | }; |
| 258 | RunParseTest("/***", expected_parts); |
| 259 | } |
| 260 | |
| 261 | TEST(ParseTest, WildcardWithMultipleModifiersPlus) { |
Ben Kelly | 18869af75 | 2021-07-14 02:08:25 | [diff] [blame] | 262 | RunParseTest("/**+", absl::InvalidArgumentError("expected end of pattern")); |
Ben Kelly | d228e3c | 2021-02-24 00:43:40 | [diff] [blame] | 263 | } |
| 264 | |
| 265 | TEST(ParseTest, WildcardWithMultipleModifiersQuestion) { |
Ben Kelly | 18869af75 | 2021-07-14 02:08:25 | [diff] [blame] | 266 | RunParseTest("/**?", absl::InvalidArgumentError("expected end of pattern")); |
Ben Kelly | d228e3c | 2021-02-24 00:43:40 | [diff] [blame] | 267 | } |
| 268 | |
| 269 | TEST(ParseTest, WildcardInGroup) { |
| 270 | std::vector<Part> expected_parts = { |
| 271 | Part(PartType::kFixed, "/f", Modifier::kNone), |
| 272 | Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"", /*value=*/"", |
| 273 | /*suffix=*/"", Modifier::kNone), |
| 274 | }; |
| 275 | RunParseTest("/f{*}", expected_parts); |
| 276 | } |
| 277 | |
| 278 | TEST(ParseTest, WildcardWithPrefixAndSuffixInGroup) { |
| 279 | std::vector<Part> expected_parts = { |
| 280 | Part(PartType::kFixed, "/", Modifier::kNone), |
| 281 | Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"f", /*value=*/"", |
| 282 | /*suffix=*/"o", Modifier::kNone), |
| 283 | }; |
| 284 | RunParseTest("/{f*o}", expected_parts); |
| 285 | } |
| 286 | |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 287 | TEST(ParseTest, Name) { |
| 288 | std::vector<Part> expected_parts = { |
| 289 | Part(PartType::kFixed, "/foo", Modifier::kNone), |
| 290 | Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"", |
| 291 | /*value=*/"", /*suffix=*/"", Modifier::kNone), |
| 292 | }; |
| 293 | RunParseTest("/foo:bar", expected_parts); |
| 294 | } |
| 295 | |
Ben Kelly | 02c1d17 | 2021-03-16 15:33:25 | [diff] [blame] | 296 | TEST(ParseTest, NameStartsWithNumber) { |
| 297 | RunParseTest("/foo/:0", absl::InvalidArgumentError("Missing parameter name")); |
| 298 | } |
| 299 | |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 300 | TEST(ParseTest, NameInGroup) { |
| 301 | std::vector<Part> expected_parts = { |
| 302 | Part(PartType::kFixed, "/foo", Modifier::kNone), |
| 303 | Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"", |
| 304 | /*value=*/"", /*suffix=*/"", Modifier::kNone), |
| 305 | }; |
| 306 | RunParseTest("/foo{:bar}", expected_parts); |
| 307 | } |
| 308 | |
| 309 | TEST(ParseTest, NameAndNameInGroup) { |
Ben Kelly | 18869af75 | 2021-07-14 02:08:25 | [diff] [blame] | 310 | RunParseTest("/foo{:bar:baz}", absl::InvalidArgumentError("expected '}'")); |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 311 | } |
| 312 | |
| 313 | TEST(ParseTest, NameWithPrefixAndSuffixInGroup) { |
| 314 | std::vector<Part> expected_parts = { |
| 315 | Part(PartType::kFixed, "/foo/", Modifier::kNone), |
| 316 | Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"data_", |
| 317 | /*value=*/"", /*suffix=*/".jpg", Modifier::kNone), |
| 318 | }; |
| 319 | RunParseTest("/foo/{data_:bar.jpg}", expected_parts); |
| 320 | } |
| 321 | |
| 322 | TEST(ParseTest, NameWithPrefix) { |
| 323 | std::vector<Part> expected_parts = { |
| 324 | Part(PartType::kFixed, "/foo", Modifier::kNone), |
| 325 | Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"/", |
| 326 | /*value=*/"", /*suffix=*/"", Modifier::kNone), |
| 327 | }; |
| 328 | RunParseTest("/foo/:bar", expected_parts); |
| 329 | } |
| 330 | |
| 331 | TEST(ParseTest, NameWithEscapedPrefix) { |
| 332 | std::vector<Part> expected_parts = { |
| 333 | Part(PartType::kFixed, "/foo/", Modifier::kNone), |
| 334 | Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"", |
| 335 | /*value=*/"", /*suffix=*/"", Modifier::kNone), |
| 336 | }; |
| 337 | RunParseTest("/foo\\/:bar", expected_parts); |
| 338 | } |
| 339 | |
| 340 | TEST(ParseTest, NameWithCustomRegex) { |
| 341 | std::vector<Part> expected_parts = { |
| 342 | Part(PartType::kFixed, "/foo", Modifier::kNone), |
| 343 | Part(PartType::kRegex, /*name=*/"bar", /*prefix=*/"", "[^/]+?", |
| 344 | /*suffix=*/"", Modifier::kNone), |
| 345 | }; |
| 346 | RunParseTest("/foo:bar([^/]+?)", expected_parts); |
| 347 | } |
| 348 | |
| 349 | TEST(ParseTest, NameWithModifier) { |
| 350 | std::vector<Part> expected_parts = { |
| 351 | Part(PartType::kSegmentWildcard, /*name=*/"foo", /*prefix=*/"/", |
| 352 | /*value=*/"", /*suffix=*/"", Modifier::kOptional), |
| 353 | }; |
| 354 | RunParseTest("/:foo?", expected_parts); |
| 355 | } |
| 356 | |
Ben Kelly | d228e3c | 2021-02-24 00:43:40 | [diff] [blame] | 357 | TEST(ParseTest, NameWithModifierStarAndWildcard) { |
| 358 | std::vector<Part> expected_parts = { |
| 359 | Part(PartType::kSegmentWildcard, /*name=*/"foo", /*prefix=*/"/", |
| 360 | /*value=*/"", /*suffix=*/"", Modifier::kZeroOrMore), |
| 361 | Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"", |
| 362 | /*value=*/"", /*suffix=*/"", Modifier::kNone), |
| 363 | }; |
| 364 | RunParseTest("/:foo**", expected_parts); |
| 365 | } |
| 366 | |
| 367 | TEST(ParseTest, NameWithModifierStarAndModifierQuestion) { |
Ben Kelly | 18869af75 | 2021-07-14 02:08:25 | [diff] [blame] | 368 | RunParseTest("/:foo*?", |
| 369 | absl::InvalidArgumentError("expected end of pattern")); |
Ben Kelly | d228e3c | 2021-02-24 00:43:40 | [diff] [blame] | 370 | } |
| 371 | |
| 372 | TEST(ParseTest, NameWithModifierStarAndModifierPlus) { |
Ben Kelly | 18869af75 | 2021-07-14 02:08:25 | [diff] [blame] | 373 | RunParseTest("/:foo*+", |
| 374 | absl::InvalidArgumentError("expected end of pattern")); |
Ben Kelly | d228e3c | 2021-02-24 00:43:40 | [diff] [blame] | 375 | } |
| 376 | |
Ben Kelly | 003c548 | 2021-08-17 19:28:17 | [diff] [blame] | 377 | TEST(ParseTest, DuplicateName) { |
| 378 | RunParseTest("/:foo/:foo", absl::InvalidArgumentError("Duplicate")); |
| 379 | } |
| 380 | |
Ben Kelly | 0e5c63e8 | 2020-11-12 21:24:08 | [diff] [blame] | 381 | } // namespace liburlpattern |