url_pattern_set_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "extensions/common/url_pattern_set.h"
  5. #include <stddef.h>
  6. #include <sstream>
  7. #include "base/containers/contains.h"
  8. #include "base/strings/string_util.h"
  9. #include "base/strings/stringprintf.h"
  10. #include "base/values.h"
  11. #include "testing/gmock/include/gmock/gmock.h"
  12. #include "testing/gtest/include/gtest/gtest.h"
  13. #include "url/gurl.h"
  14. namespace extensions {
  15. namespace {
  16. void AddPattern(URLPatternSet* set, const std::string& pattern) {
  17. int schemes = URLPattern::SCHEME_ALL;
  18. set->AddPattern(URLPattern(schemes, pattern));
  19. }
  20. } // namespace
  21. TEST(URLPatternSetTest, Empty) {
  22. URLPatternSet set;
  23. EXPECT_FALSE(set.MatchesURL(GURL("http://www.foo.com/bar")));
  24. EXPECT_FALSE(set.MatchesURL(GURL()));
  25. EXPECT_FALSE(set.MatchesURL(GURL("invalid")));
  26. }
  27. TEST(URLPatternSetTest, One) {
  28. URLPatternSet set;
  29. AddPattern(&set, "http://www.google.com/*");
  30. EXPECT_TRUE(set.MatchesURL(GURL("http://www.google.com/")));
  31. EXPECT_TRUE(set.MatchesURL(GURL("http://www.google.com/monkey")));
  32. EXPECT_FALSE(set.MatchesURL(GURL("https://www.google.com/")));
  33. EXPECT_FALSE(set.MatchesURL(GURL("https://www.microsoft.com/")));
  34. }
  35. TEST(URLPatternSetTest, Two) {
  36. URLPatternSet set;
  37. AddPattern(&set, "http://www.google.com/*");
  38. AddPattern(&set, "http://www.yahoo.com/*");
  39. EXPECT_TRUE(set.MatchesURL(GURL("http://www.google.com/monkey")));
  40. EXPECT_TRUE(set.MatchesURL(GURL("http://www.yahoo.com/monkey")));
  41. EXPECT_FALSE(set.MatchesURL(GURL("https://www.apple.com/monkey")));
  42. }
  43. TEST(URLPatternSetTest, StreamOperatorEmpty) {
  44. URLPatternSet set;
  45. std::ostringstream stream;
  46. stream << set;
  47. EXPECT_EQ("{ }", stream.str());
  48. }
  49. TEST(URLPatternSetTest, StreamOperatorOne) {
  50. URLPatternSet set;
  51. AddPattern(&set, "http://www.google.com/*");
  52. std::ostringstream stream;
  53. stream << set;
  54. EXPECT_EQ("{ \"http://www.google.com/*\" }", stream.str());
  55. }
  56. TEST(URLPatternSetTest, StreamOperatorTwo) {
  57. URLPatternSet set;
  58. AddPattern(&set, "http://www.google.com/*");
  59. AddPattern(&set, "http://www.yahoo.com/*");
  60. std::ostringstream stream;
  61. stream << set;
  62. EXPECT_EQ("{ \"http://www.google.com/*\", \"http://www.yahoo.com/*\" }",
  63. stream.str());
  64. }
  65. TEST(URLPatternSetTest, OverlapsWith) {
  66. URLPatternSet set1;
  67. AddPattern(&set1, "http://www.google.com/f*");
  68. AddPattern(&set1, "http://www.yahoo.com/b*");
  69. URLPatternSet set2;
  70. AddPattern(&set2, "http://www.reddit.com/f*");
  71. AddPattern(&set2, "http://www.yahoo.com/z*");
  72. URLPatternSet set3;
  73. AddPattern(&set3, "http://www.google.com/q/*");
  74. AddPattern(&set3, "http://www.yahoo.com/b/*");
  75. EXPECT_FALSE(set1.OverlapsWith(set2));
  76. EXPECT_FALSE(set2.OverlapsWith(set1));
  77. EXPECT_TRUE(set1.OverlapsWith(set3));
  78. EXPECT_TRUE(set3.OverlapsWith(set1));
  79. }
  80. TEST(URLPatternSetTest, CreateDifference) {
  81. URLPatternSet expected;
  82. URLPatternSet set1;
  83. URLPatternSet set2;
  84. AddPattern(&set1, "http://www.google.com/f*");
  85. AddPattern(&set1, "http://www.yahoo.com/b*");
  86. // Subtract an empty set.
  87. URLPatternSet result = URLPatternSet::CreateDifference(set1, set2);
  88. EXPECT_EQ(set1, result);
  89. // Subtract a real set.
  90. AddPattern(&set2, "http://www.reddit.com/f*");
  91. AddPattern(&set2, "http://www.yahoo.com/z*");
  92. AddPattern(&set2, "http://www.google.com/f*");
  93. AddPattern(&expected, "http://www.yahoo.com/b*");
  94. result = URLPatternSet::CreateDifference(set1, set2);
  95. EXPECT_EQ(expected, result);
  96. EXPECT_FALSE(result.is_empty());
  97. EXPECT_TRUE(set1.Contains(result));
  98. EXPECT_FALSE(result.Contains(set2));
  99. EXPECT_FALSE(set2.Contains(result));
  100. URLPatternSet intersection = URLPatternSet::CreateIntersection(
  101. result, set2, URLPatternSet::IntersectionBehavior::kStringComparison);
  102. EXPECT_TRUE(intersection.is_empty());
  103. }
  104. TEST(URLPatternSetTest, CreateIntersection_StringComparison) {
  105. URLPatternSet empty_set;
  106. URLPatternSet expected;
  107. URLPatternSet set1;
  108. AddPattern(&set1, "http://www.google.com/f*");
  109. AddPattern(&set1, "http://www.yahoo.com/b*");
  110. // Intersection with an empty set.
  111. URLPatternSet result = URLPatternSet::CreateIntersection(
  112. set1, empty_set, URLPatternSet::IntersectionBehavior::kStringComparison);
  113. EXPECT_EQ(expected, result);
  114. EXPECT_TRUE(result.is_empty());
  115. EXPECT_TRUE(empty_set.Contains(result));
  116. EXPECT_TRUE(result.Contains(empty_set));
  117. EXPECT_TRUE(set1.Contains(result));
  118. // Intersection with a real set.
  119. URLPatternSet set2;
  120. AddPattern(&set2, "http://www.reddit.com/f*");
  121. AddPattern(&set2, "http://www.yahoo.com/z*");
  122. AddPattern(&set2, "http://www.google.com/f*");
  123. AddPattern(&expected, "http://www.google.com/f*");
  124. result = URLPatternSet::CreateIntersection(
  125. set1, set2, URLPatternSet::IntersectionBehavior::kStringComparison);
  126. EXPECT_EQ(expected, result);
  127. EXPECT_FALSE(result.is_empty());
  128. EXPECT_TRUE(set1.Contains(result));
  129. EXPECT_TRUE(set2.Contains(result));
  130. }
  131. TEST(URLPatternSetTest, CreateIntersection_PatternsContainedByBoth) {
  132. {
  133. URLPatternSet set1;
  134. AddPattern(&set1, "http://*.google.com/*");
  135. AddPattern(&set1, "http://*.yahoo.com/*");
  136. URLPatternSet set2;
  137. AddPattern(&set2, "http://google.com/*");
  138. // The semantic intersection should contain only those patterns that are in
  139. // both set 1 and set 2, or "http://google.com/*".
  140. URLPatternSet intersection = URLPatternSet::CreateIntersection(
  141. set1, set2,
  142. URLPatternSet::IntersectionBehavior::kPatternsContainedByBoth);
  143. ASSERT_EQ(1u, intersection.size());
  144. EXPECT_EQ("http://google.com/*", intersection.begin()->GetAsString());
  145. }
  146. {
  147. // IntersectionBehavior::kPatternsContainedByBoth doesn't handle funny
  148. // intersections, where the resultant pattern is neither of the two
  149. // compared patterns. So the intersection of these two is not
  150. // http://www.google.com/*, but rather nothing.
  151. URLPatternSet set1;
  152. AddPattern(&set1, "http://*/*");
  153. URLPatternSet set2;
  154. AddPattern(&set2, "*://www.google.com/*");
  155. EXPECT_TRUE(
  156. URLPatternSet::CreateIntersection(
  157. set1, set2,
  158. URLPatternSet::IntersectionBehavior::kPatternsContainedByBoth)
  159. .is_empty());
  160. }
  161. }
  162. TEST(URLPatternSetTest, CreateIntersection_Detailed) {
  163. struct {
  164. std::vector<std::string> set1;
  165. std::vector<std::string> set2;
  166. std::vector<std::string> expected_intersection;
  167. } test_cases[] = {
  168. {{"https://*.google.com/*", "https://chromium.org/*"},
  169. {"*://maps.google.com/*", "*://chromium.org/foo"},
  170. {"https://maps.google.com/*", "https://chromium.org/foo"}},
  171. {{"https://*/*", "http://*/*"},
  172. {"*://google.com/*", "*://chromium.org/*"},
  173. {"https://google.com/*", "http://google.com/*", "https://chromium.org/*",
  174. "http://chromium.org/*"}},
  175. {{"<all_urls>"},
  176. {"https://chromium.org/*", "*://google.com/*"},
  177. {"https://chromium.org/*", "*://google.com/*"}},
  178. {{"*://*/maps", "*://*.example.com/*"},
  179. {"https://*.google.com/*", "https://www.example.com/*"},
  180. {"https://*.google.com/maps", "https://www.example.com/*"}},
  181. {{"https://*/maps", "https://*.google.com/*"},
  182. {"https://*.google.com/*"},
  183. {"https://*.google.com/*"}},
  184. {{"http://*/*"}, {"https://*/*"}, {}},
  185. {{"https://*.google.com/*", "https://maps.google.com/*"},
  186. {"https://*.google.com/*", "https://*/*"},
  187. // NOTE: We don't currently do any additional "collapsing" step after
  188. // finding the intersection. We potentially could, to reduce the number
  189. // of patterns we need to store.
  190. {"https://*.google.com/*", "https://maps.google.com/*"}},
  191. };
  192. constexpr int kValidSchemes = URLPattern::SCHEME_ALL;
  193. constexpr char kTestCaseDescriptionTemplate[] =
  194. "Running Test Case:\n"
  195. " Set1: %s\n"
  196. " Set2: %s\n"
  197. " Expected Result: %s";
  198. for (const auto& test_case : test_cases) {
  199. SCOPED_TRACE(base::StringPrintf(
  200. kTestCaseDescriptionTemplate,
  201. base::JoinString(test_case.set1, ", ").c_str(),
  202. base::JoinString(test_case.set2, ", ").c_str(),
  203. base::JoinString(test_case.expected_intersection, ", ").c_str()));
  204. URLPatternSet set1;
  205. for (const auto& pattern_str : test_case.set1) {
  206. URLPattern pattern(kValidSchemes);
  207. ASSERT_EQ(URLPattern::ParseResult::kSuccess, pattern.Parse(pattern_str))
  208. << "Failed to parse: " << pattern_str;
  209. set1.AddPattern(pattern);
  210. }
  211. URLPatternSet set2;
  212. for (const auto& pattern_str : test_case.set2) {
  213. URLPattern pattern(kValidSchemes);
  214. ASSERT_EQ(URLPattern::ParseResult::kSuccess, pattern.Parse(pattern_str))
  215. << "Failed to parse: " << pattern_str;
  216. set2.AddPattern(pattern);
  217. }
  218. URLPatternSet intersection1 = URLPatternSet::CreateIntersection(
  219. set1, set2, URLPatternSet::IntersectionBehavior::kDetailed);
  220. URLPatternSet intersection2 = URLPatternSet::CreateIntersection(
  221. set2, set1, URLPatternSet::IntersectionBehavior::kDetailed);
  222. EXPECT_THAT(
  223. *intersection1.ToStringVector(),
  224. testing::UnorderedElementsAreArray(test_case.expected_intersection));
  225. EXPECT_THAT(
  226. *intersection2.ToStringVector(),
  227. testing::UnorderedElementsAreArray(test_case.expected_intersection));
  228. }
  229. }
  230. TEST(URLPatternSetTest, CreateUnion) {
  231. URLPatternSet empty_set;
  232. URLPatternSet set1;
  233. AddPattern(&set1, "http://www.google.com/f*");
  234. AddPattern(&set1, "http://www.yahoo.com/b*");
  235. URLPatternSet expected;
  236. AddPattern(&expected, "http://www.google.com/f*");
  237. AddPattern(&expected, "http://www.yahoo.com/b*");
  238. // Union with an empty set.
  239. URLPatternSet result = URLPatternSet::CreateUnion(set1, empty_set);
  240. EXPECT_EQ(expected, result);
  241. // Union with a real set.
  242. URLPatternSet set2;
  243. AddPattern(&set2, "http://www.reddit.com/f*");
  244. AddPattern(&set2, "http://www.yahoo.com/z*");
  245. AddPattern(&set2, "http://www.google.com/f*");
  246. AddPattern(&expected, "http://www.reddit.com/f*");
  247. AddPattern(&expected, "http://www.yahoo.com/z*");
  248. result = URLPatternSet::CreateUnion(set1, set2);
  249. EXPECT_EQ(expected, result);
  250. }
  251. TEST(URLPatternSetTest, Contains) {
  252. URLPatternSet set1;
  253. URLPatternSet set2;
  254. URLPatternSet empty_set;
  255. AddPattern(&set1, "http://www.google.com/*");
  256. AddPattern(&set1, "http://www.yahoo.com/*");
  257. AddPattern(&set2, "http://www.reddit.com/*");
  258. EXPECT_FALSE(set1.Contains(set2));
  259. EXPECT_TRUE(set1.Contains(empty_set));
  260. EXPECT_FALSE(empty_set.Contains(set1));
  261. AddPattern(&set2, "http://www.yahoo.com/*");
  262. EXPECT_FALSE(set1.Contains(set2));
  263. EXPECT_FALSE(set2.Contains(set1));
  264. AddPattern(&set2, "http://www.google.com/*");
  265. EXPECT_FALSE(set1.Contains(set2));
  266. EXPECT_TRUE(set2.Contains(set1));
  267. // Note that this checks if individual patterns contain other patterns, not
  268. // just equality. For example:
  269. AddPattern(&set1, "http://*.reddit.com/*");
  270. EXPECT_TRUE(set1.Contains(set2));
  271. EXPECT_FALSE(set2.Contains(set1));
  272. }
  273. TEST(URLPatternSetTest, Duplicates) {
  274. URLPatternSet set1;
  275. URLPatternSet set2;
  276. AddPattern(&set1, "http://www.google.com/*");
  277. AddPattern(&set2, "http://www.google.com/*");
  278. AddPattern(&set1, "http://www.google.com/*");
  279. // The sets should still be equal after adding a duplicate.
  280. EXPECT_EQ(set2, set1);
  281. }
  282. TEST(URLPatternSetTest, ToValueAndPopulate) {
  283. URLPatternSet set1;
  284. URLPatternSet set2;
  285. std::vector<std::string> patterns;
  286. patterns.push_back("http://www.google.com/*");
  287. patterns.push_back("http://www.yahoo.com/*");
  288. for (size_t i = 0; i < patterns.size(); ++i)
  289. AddPattern(&set1, patterns[i]);
  290. std::string error;
  291. bool allow_file_access = false;
  292. std::unique_ptr<base::ListValue> value(set1.ToValue());
  293. set2.Populate(*value, URLPattern::SCHEME_ALL, allow_file_access, &error);
  294. EXPECT_EQ(set1, set2);
  295. set2.ClearPatterns();
  296. set2.Populate(patterns, URLPattern::SCHEME_ALL, allow_file_access, &error);
  297. EXPECT_EQ(set1, set2);
  298. }
  299. TEST(URLPatternSetTest, AddOrigin) {
  300. URLPatternSet set;
  301. EXPECT_TRUE(set.AddOrigin(
  302. URLPattern::SCHEME_ALL, GURL("https://www.google.com/")));
  303. EXPECT_TRUE(set.MatchesURL(GURL("https://www.google.com/foo/bar")));
  304. EXPECT_FALSE(set.MatchesURL(GURL("http://www.google.com/foo/bar")));
  305. EXPECT_FALSE(set.MatchesURL(GURL("https://en.google.com/foo/bar")));
  306. set.ClearPatterns();
  307. EXPECT_TRUE(set.AddOrigin(
  308. URLPattern::SCHEME_ALL, GURL("https://google.com/")));
  309. EXPECT_FALSE(set.MatchesURL(GURL("https://www.google.com/foo/bar")));
  310. EXPECT_TRUE(set.MatchesURL(GURL("https://google.com/foo/bar")));
  311. EXPECT_FALSE(set.AddOrigin(
  312. URLPattern::SCHEME_HTTP, GURL("https://google.com/")));
  313. }
  314. TEST(URLPatternSet, AddOriginIPv6) {
  315. {
  316. URLPatternSet set;
  317. EXPECT_TRUE(set.AddOrigin(URLPattern::SCHEME_HTTP,
  318. GURL("http://[2607:f8b0:4005:805::200e]/*")));
  319. }
  320. {
  321. URLPatternSet set;
  322. EXPECT_TRUE(set.AddOrigin(URLPattern::SCHEME_HTTP,
  323. GURL("http://[2607:f8b0:4005:805::200e]/")));
  324. }
  325. }
  326. TEST(URLPatternSetTest, ToStringVector) {
  327. URLPatternSet set;
  328. AddPattern(&set, "https://google.com/");
  329. AddPattern(&set, "https://google.com/");
  330. AddPattern(&set, "https://yahoo.com/");
  331. std::unique_ptr<std::vector<std::string>> string_vector(set.ToStringVector());
  332. EXPECT_EQ(2UL, string_vector->size());
  333. EXPECT_TRUE(base::Contains(*string_vector, "https://google.com/"));
  334. EXPECT_TRUE(base::Contains(*string_vector, "https://yahoo.com/"));
  335. }
  336. } // namespace extensions