parse_unittest.cc 12 KB

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