123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by an MIT-style license that can be
- // found in the LICENSE file or at https://opensource.org/licenses/MIT.
- #include "third_party/liburlpattern/parse.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/abseil-cpp/absl/strings/str_format.h"
- #include "third_party/liburlpattern/pattern.h"
- namespace {
- absl::StatusOr<std::string> PassThrough(absl::string_view input) {
- return std::string(input);
- }
- } // namespace
- namespace liburlpattern {
- absl::StatusOr<std::string> ToUpper(absl::string_view input) {
- std::string output;
- std::transform(input.begin(), input.end(), std::back_inserter(output),
- [](unsigned char c) { return std::toupper(c); });
- return output;
- }
- void RunParseTest(absl::string_view pattern,
- absl::StatusOr<std::vector<Part>> expected,
- EncodeCallback callback = PassThrough) {
- auto result = Parse(pattern, std::move(callback));
- ASSERT_EQ(result.ok(), expected.ok())
- << "parse status '" << result.status() << "' for: " << pattern;
- if (!expected.ok()) {
- ASSERT_EQ(result.status().code(), expected.status().code())
- << "parse status code for: " << pattern;
- EXPECT_NE(result.status().message().find(expected.status().message()),
- std::string::npos)
- << "parse message '" << result.status().message()
- << "' does not contain '" << expected.status().message()
- << "' for: " << pattern;
- return;
- }
- const auto& expected_part_list = expected.value();
- const auto& part_list = result.value().PartList();
- EXPECT_EQ(part_list.size(), expected_part_list.size())
- << "parser should produce expected number of parts for: " << pattern;
- for (size_t i = 0; i < part_list.size() && i < expected_part_list.size();
- ++i) {
- EXPECT_EQ(part_list[i], expected_part_list[i])
- << "token at index " << i << " wrong for: " << pattern;
- }
- }
- TEST(ParseTest, EmptyPattern) {
- RunParseTest("", std::vector<Part>());
- }
- TEST(ParseTest, EncoderCallback) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/FOO/BAR", Modifier::kNone),
- };
- RunParseTest("/foo/bar", expected_parts, ToUpper);
- }
- TEST(ParseTest, Fixed) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kNone),
- };
- RunParseTest("/foo", expected_parts);
- }
- TEST(ParseTest, FixedInGroup) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kNone),
- };
- RunParseTest("{/foo}", expected_parts);
- }
- TEST(ParseTest, FixedAndFixedInGroup) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kNone),
- };
- RunParseTest("/{foo}", expected_parts);
- }
- TEST(ParseTest, FixedInGroupAndFixed) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kNone),
- };
- RunParseTest("{/}foo", expected_parts);
- }
- TEST(ParseTest, FixedInGroupAndFixedInGroup) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kNone),
- };
- RunParseTest("{/}{foo}", expected_parts);
- }
- TEST(ParseTest, FixedAndEmptyGroup) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kNone),
- };
- RunParseTest("/f{}oo", expected_parts);
- }
- TEST(ParseTest, FixedInGroupWithOptionalModifier) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kOptional),
- };
- RunParseTest("{/foo}?", expected_parts);
- }
- TEST(ParseTest, FixedInGroupWithZeroOrMoreModifier) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kZeroOrMore),
- };
- RunParseTest("{/foo}*", expected_parts);
- }
- TEST(ParseTest, FixedInGroupWithOneOrMoreModifier) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kOneOrMore),
- };
- RunParseTest("{/foo}+", expected_parts);
- }
- TEST(ParseTest, FixedInEarlyTerminatedGroup) {
- RunParseTest("{/foo", absl::InvalidArgumentError("expected '}'"));
- }
- TEST(ParseTest, FixedInUnbalancedGroup) {
- RunParseTest("{/foo?", absl::InvalidArgumentError("expected '}'"));
- }
- TEST(ParseTest, FixedWithModifier) {
- RunParseTest("/foo?", absl::InvalidArgumentError("Unexpected modifier"));
- }
- TEST(ParseTest, Regex) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/f", Modifier::kNone),
- Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"", "oo", /*suffix=*/"",
- Modifier::kNone),
- };
- RunParseTest("/f(oo)", expected_parts);
- }
- TEST(ParseTest, RegexInGroup) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/f", Modifier::kNone),
- Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"", "oo", /*suffix=*/"",
- Modifier::kNone),
- };
- RunParseTest("/f{(oo)}", expected_parts);
- }
- TEST(ParseTest, RegexWithPrefixAndSuffixInGroup) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/", Modifier::kNone),
- Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"f", "o", /*suffix=*/"o",
- Modifier::kNone),
- };
- RunParseTest("/{f(o)o}", expected_parts);
- }
- TEST(ParseTest, RegexAndRegexInGroup) {
- RunParseTest("/f{(o)(o)}", absl::InvalidArgumentError("expected '}'"));
- }
- TEST(ParseTest, RegexWithPrefix) {
- std::vector<Part> expected_parts = {
- Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"/", "foo", /*suffix=*/"",
- Modifier::kNone),
- };
- RunParseTest("/(foo)", expected_parts);
- }
- TEST(ParseTest, RegexWithNameAndPrefix) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kNone),
- Part(PartType::kRegex, /*name=*/"bar", /*prefix=*/"/", "[^/]+?",
- /*suffix=*/"", Modifier::kNone),
- };
- RunParseTest("/foo/:bar([^/]+?)", expected_parts);
- }
- TEST(ParseTest, RegexWithNameAndPrefixInGroup) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo/", Modifier::kNone),
- Part(PartType::kRegex, /*name=*/"bar", /*prefix=*/"", "[^/]+?",
- /*suffix=*/"", Modifier::kNone),
- };
- RunParseTest("/foo/{:bar([^/]+?)}", expected_parts);
- }
- TEST(ParseTest, RegexWithModifier) {
- std::vector<Part> expected_parts = {
- Part(PartType::kRegex, /*name=*/"0", /*prefix=*/"/", "foo",
- /*suffix=*/"", Modifier::kOptional),
- };
- RunParseTest("/(foo)?", expected_parts);
- }
- TEST(ParseTest, RegexLikeFullWildcard) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"",
- /*suffix=*/"", Modifier::kNone),
- };
- RunParseTest("/(.*)", expected_parts);
- }
- TEST(ParseTest, Wildcard) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"",
- /*suffix=*/"", Modifier::kNone),
- };
- RunParseTest("/*", expected_parts);
- }
- TEST(ParseTest, WildcardWithModifierStar) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"",
- /*suffix=*/"", Modifier::kZeroOrMore),
- };
- RunParseTest("/**", expected_parts);
- }
- TEST(ParseTest, WildcardWithModifierPlus) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"",
- /*suffix=*/"", Modifier::kOneOrMore),
- };
- RunParseTest("/*+", expected_parts);
- }
- TEST(ParseTest, WildcardWithModifierQuestion) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"",
- /*suffix=*/"", Modifier::kOptional),
- };
- RunParseTest("/*?", expected_parts);
- }
- TEST(ParseTest, WildcardFollowingWildcardWithModifierStart) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"/", /*value=*/"",
- /*suffix=*/"", Modifier::kZeroOrMore),
- Part(PartType::kFullWildcard, /*name=*/"1", /*prefix=*/"", /*value=*/"",
- /*suffix=*/"", Modifier::kNone),
- };
- RunParseTest("/***", expected_parts);
- }
- TEST(ParseTest, WildcardWithMultipleModifiersPlus) {
- RunParseTest("/**+", absl::InvalidArgumentError("expected end of pattern"));
- }
- TEST(ParseTest, WildcardWithMultipleModifiersQuestion) {
- RunParseTest("/**?", absl::InvalidArgumentError("expected end of pattern"));
- }
- TEST(ParseTest, WildcardInGroup) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/f", Modifier::kNone),
- Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"", /*value=*/"",
- /*suffix=*/"", Modifier::kNone),
- };
- RunParseTest("/f{*}", expected_parts);
- }
- TEST(ParseTest, WildcardWithPrefixAndSuffixInGroup) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/", Modifier::kNone),
- Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"f", /*value=*/"",
- /*suffix=*/"o", Modifier::kNone),
- };
- RunParseTest("/{f*o}", expected_parts);
- }
- TEST(ParseTest, Name) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kNone),
- Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"",
- /*value=*/"", /*suffix=*/"", Modifier::kNone),
- };
- RunParseTest("/foo:bar", expected_parts);
- }
- TEST(ParseTest, NameStartsWithNumber) {
- RunParseTest("/foo/:0", absl::InvalidArgumentError("Missing parameter name"));
- }
- TEST(ParseTest, NameInGroup) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kNone),
- Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"",
- /*value=*/"", /*suffix=*/"", Modifier::kNone),
- };
- RunParseTest("/foo{:bar}", expected_parts);
- }
- TEST(ParseTest, NameAndNameInGroup) {
- RunParseTest("/foo{:bar:baz}", absl::InvalidArgumentError("expected '}'"));
- }
- TEST(ParseTest, NameWithPrefixAndSuffixInGroup) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo/", Modifier::kNone),
- Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"data_",
- /*value=*/"", /*suffix=*/".jpg", Modifier::kNone),
- };
- RunParseTest("/foo/{data_:bar.jpg}", expected_parts);
- }
- TEST(ParseTest, NameWithPrefix) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kNone),
- Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"/",
- /*value=*/"", /*suffix=*/"", Modifier::kNone),
- };
- RunParseTest("/foo/:bar", expected_parts);
- }
- TEST(ParseTest, NameWithEscapedPrefix) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo/", Modifier::kNone),
- Part(PartType::kSegmentWildcard, /*name=*/"bar", /*prefix=*/"",
- /*value=*/"", /*suffix=*/"", Modifier::kNone),
- };
- RunParseTest("/foo\\/:bar", expected_parts);
- }
- TEST(ParseTest, NameWithCustomRegex) {
- std::vector<Part> expected_parts = {
- Part(PartType::kFixed, "/foo", Modifier::kNone),
- Part(PartType::kRegex, /*name=*/"bar", /*prefix=*/"", "[^/]+?",
- /*suffix=*/"", Modifier::kNone),
- };
- RunParseTest("/foo:bar([^/]+?)", expected_parts);
- }
- TEST(ParseTest, NameWithModifier) {
- std::vector<Part> expected_parts = {
- Part(PartType::kSegmentWildcard, /*name=*/"foo", /*prefix=*/"/",
- /*value=*/"", /*suffix=*/"", Modifier::kOptional),
- };
- RunParseTest("/:foo?", expected_parts);
- }
- TEST(ParseTest, NameWithModifierStarAndWildcard) {
- std::vector<Part> expected_parts = {
- Part(PartType::kSegmentWildcard, /*name=*/"foo", /*prefix=*/"/",
- /*value=*/"", /*suffix=*/"", Modifier::kZeroOrMore),
- Part(PartType::kFullWildcard, /*name=*/"0", /*prefix=*/"",
- /*value=*/"", /*suffix=*/"", Modifier::kNone),
- };
- RunParseTest("/:foo**", expected_parts);
- }
- TEST(ParseTest, NameWithModifierStarAndModifierQuestion) {
- RunParseTest("/:foo*?",
- absl::InvalidArgumentError("expected end of pattern"));
- }
- TEST(ParseTest, NameWithModifierStarAndModifierPlus) {
- RunParseTest("/:foo*+",
- absl::InvalidArgumentError("expected end of pattern"));
- }
- TEST(ParseTest, DuplicateName) {
- RunParseTest("/:foo/:foo", absl::InvalidArgumentError("Duplicate"));
- }
- } // namespace liburlpattern
|