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
5#include "extensions/common/url_pattern_set.h"
6
7#include <sstream>
8
9#include "base/values.h"
10#include "testing/gtest/include/gtest/gtest.h"
11#include "url/gurl.h"
12
13namespace extensions {
14
15namespace {
16
17void AddPattern(URLPatternSet* set, const std::string& pattern) {
18  int schemes = URLPattern::SCHEME_ALL;
19  set->AddPattern(URLPattern(schemes, pattern));
20}
21
22URLPatternSet Patterns(const std::string& pattern) {
23  URLPatternSet set;
24  AddPattern(&set, pattern);
25  return set;
26}
27
28URLPatternSet Patterns(const std::string& pattern1,
29                       const std::string& pattern2) {
30  URLPatternSet set;
31  AddPattern(&set, pattern1);
32  AddPattern(&set, pattern2);
33  return set;
34}
35
36}  // namespace
37
38TEST(URLPatternSetTest, Empty) {
39  URLPatternSet set;
40  EXPECT_FALSE(set.MatchesURL(GURL("http://www.foo.com/bar")));
41  EXPECT_FALSE(set.MatchesURL(GURL()));
42  EXPECT_FALSE(set.MatchesURL(GURL("invalid")));
43}
44
45TEST(URLPatternSetTest, One) {
46  URLPatternSet set;
47  AddPattern(&set, "http://www.google.com/*");
48
49  EXPECT_TRUE(set.MatchesURL(GURL("http://www.google.com/")));
50  EXPECT_TRUE(set.MatchesURL(GURL("http://www.google.com/monkey")));
51  EXPECT_FALSE(set.MatchesURL(GURL("https://www.google.com/")));
52  EXPECT_FALSE(set.MatchesURL(GURL("https://www.microsoft.com/")));
53}
54
55TEST(URLPatternSetTest, Two) {
56  URLPatternSet set;
57  AddPattern(&set, "http://www.google.com/*");
58  AddPattern(&set, "http://www.yahoo.com/*");
59
60  EXPECT_TRUE(set.MatchesURL(GURL("http://www.google.com/monkey")));
61  EXPECT_TRUE(set.MatchesURL(GURL("http://www.yahoo.com/monkey")));
62  EXPECT_FALSE(set.MatchesURL(GURL("https://www.apple.com/monkey")));
63}
64
65TEST(URLPatternSetTest, StreamOperatorEmpty) {
66  URLPatternSet set;
67
68  std::ostringstream stream;
69  stream << set;
70  EXPECT_EQ("{ }", stream.str());
71}
72
73TEST(URLPatternSetTest, StreamOperatorOne) {
74  URLPatternSet set;
75  AddPattern(&set, "http://www.google.com/*");
76
77  std::ostringstream stream;
78  stream << set;
79  EXPECT_EQ("{ \"http://www.google.com/*\" }", stream.str());
80}
81
82TEST(URLPatternSetTest, StreamOperatorTwo) {
83  URLPatternSet set;
84  AddPattern(&set, "http://www.google.com/*");
85  AddPattern(&set, "http://www.yahoo.com/*");
86
87  std::ostringstream stream;
88  stream << set;
89  EXPECT_EQ("{ \"http://www.google.com/*\", \"http://www.yahoo.com/*\" }",
90            stream.str());
91}
92
93TEST(URLPatternSetTest, OverlapsWith) {
94  URLPatternSet set1;
95  AddPattern(&set1, "http://www.google.com/f*");
96  AddPattern(&set1, "http://www.yahoo.com/b*");
97
98  URLPatternSet set2;
99  AddPattern(&set2, "http://www.reddit.com/f*");
100  AddPattern(&set2, "http://www.yahoo.com/z*");
101
102  URLPatternSet set3;
103  AddPattern(&set3, "http://www.google.com/q/*");
104  AddPattern(&set3, "http://www.yahoo.com/b/*");
105
106  EXPECT_FALSE(set1.OverlapsWith(set2));
107  EXPECT_FALSE(set2.OverlapsWith(set1));
108
109  EXPECT_TRUE(set1.OverlapsWith(set3));
110  EXPECT_TRUE(set3.OverlapsWith(set1));
111}
112
113TEST(URLPatternSetTest, CreateDifference) {
114  URLPatternSet expected;
115  URLPatternSet set1;
116  URLPatternSet set2;
117  AddPattern(&set1, "http://www.google.com/f*");
118  AddPattern(&set1, "http://www.yahoo.com/b*");
119
120  // Subtract an empty set.
121  URLPatternSet result;
122  URLPatternSet::CreateDifference(set1, set2, &result);
123  EXPECT_EQ(set1, result);
124
125  // Subtract a real set.
126  AddPattern(&set2, "http://www.reddit.com/f*");
127  AddPattern(&set2, "http://www.yahoo.com/z*");
128  AddPattern(&set2, "http://www.google.com/f*");
129
130  AddPattern(&expected, "http://www.yahoo.com/b*");
131
132  result.ClearPatterns();
133  URLPatternSet::CreateDifference(set1, set2, &result);
134  EXPECT_EQ(expected, result);
135  EXPECT_FALSE(result.is_empty());
136  EXPECT_TRUE(set1.Contains(result));
137  EXPECT_FALSE(result.Contains(set2));
138  EXPECT_FALSE(set2.Contains(result));
139
140  URLPatternSet intersection;
141  URLPatternSet::CreateIntersection(result, set2, &intersection);
142  EXPECT_TRUE(intersection.is_empty());
143}
144
145TEST(URLPatternSetTest, CreateIntersection) {
146  URLPatternSet empty_set;
147  URLPatternSet expected;
148  URLPatternSet set1;
149  AddPattern(&set1, "http://www.google.com/f*");
150  AddPattern(&set1, "http://www.yahoo.com/b*");
151
152  // Intersection with an empty set.
153  URLPatternSet result;
154  URLPatternSet::CreateIntersection(set1, empty_set, &result);
155  EXPECT_EQ(expected, result);
156  EXPECT_TRUE(result.is_empty());
157  EXPECT_TRUE(empty_set.Contains(result));
158  EXPECT_TRUE(result.Contains(empty_set));
159  EXPECT_TRUE(set1.Contains(result));
160
161  // Intersection with a real set.
162  URLPatternSet set2;
163  AddPattern(&set2, "http://www.reddit.com/f*");
164  AddPattern(&set2, "http://www.yahoo.com/z*");
165  AddPattern(&set2, "http://www.google.com/f*");
166
167  AddPattern(&expected, "http://www.google.com/f*");
168
169  result.ClearPatterns();
170  URLPatternSet::CreateIntersection(set1, set2, &result);
171  EXPECT_EQ(expected, result);
172  EXPECT_FALSE(result.is_empty());
173  EXPECT_TRUE(set1.Contains(result));
174  EXPECT_TRUE(set2.Contains(result));
175}
176
177TEST(URLPatternSetTest, CreateUnion) {
178  URLPatternSet empty_set;
179
180  URLPatternSet set1;
181  AddPattern(&set1, "http://www.google.com/f*");
182  AddPattern(&set1, "http://www.yahoo.com/b*");
183
184  URLPatternSet expected;
185  AddPattern(&expected, "http://www.google.com/f*");
186  AddPattern(&expected, "http://www.yahoo.com/b*");
187
188  // Union with an empty set.
189  URLPatternSet result;
190  URLPatternSet::CreateUnion(set1, empty_set, &result);
191  EXPECT_EQ(expected, result);
192
193  // Union with a real set.
194  URLPatternSet set2;
195  AddPattern(&set2, "http://www.reddit.com/f*");
196  AddPattern(&set2, "http://www.yahoo.com/z*");
197  AddPattern(&set2, "http://www.google.com/f*");
198
199  AddPattern(&expected, "http://www.reddit.com/f*");
200  AddPattern(&expected, "http://www.yahoo.com/z*");
201
202  result.ClearPatterns();
203  URLPatternSet::CreateUnion(set1, set2, &result);
204  EXPECT_EQ(expected, result);
205}
206
207TEST(URLPatternSetTest, Contains) {
208  URLPatternSet set1;
209  URLPatternSet set2;
210  URLPatternSet empty_set;
211
212  AddPattern(&set1, "http://www.google.com/*");
213  AddPattern(&set1, "http://www.yahoo.com/*");
214
215  AddPattern(&set2, "http://www.reddit.com/*");
216
217  EXPECT_FALSE(set1.Contains(set2));
218  EXPECT_TRUE(set1.Contains(empty_set));
219  EXPECT_FALSE(empty_set.Contains(set1));
220
221  AddPattern(&set2, "http://www.yahoo.com/*");
222
223  EXPECT_FALSE(set1.Contains(set2));
224  EXPECT_FALSE(set2.Contains(set1));
225
226  AddPattern(&set2, "http://www.google.com/*");
227
228  EXPECT_FALSE(set1.Contains(set2));
229  EXPECT_TRUE(set2.Contains(set1));
230
231  // Note that this checks if individual patterns contain other patterns, not
232  // just equality. For example:
233  AddPattern(&set1, "http://*.reddit.com/*");
234  EXPECT_TRUE(set1.Contains(set2));
235  EXPECT_FALSE(set2.Contains(set1));
236}
237
238TEST(URLPatternSetTest, Duplicates) {
239  URLPatternSet set1;
240  URLPatternSet set2;
241
242  AddPattern(&set1, "http://www.google.com/*");
243  AddPattern(&set2, "http://www.google.com/*");
244
245  AddPattern(&set1, "http://www.google.com/*");
246
247  // The sets should still be equal after adding a duplicate.
248  EXPECT_EQ(set2, set1);
249}
250
251TEST(URLPatternSetTest, ToValueAndPopulate) {
252  URLPatternSet set1;
253  URLPatternSet set2;
254
255  std::vector<std::string> patterns;
256  patterns.push_back("http://www.google.com/*");
257  patterns.push_back("http://www.yahoo.com/*");
258
259  for (size_t i = 0; i < patterns.size(); ++i)
260    AddPattern(&set1, patterns[i]);
261
262  std::string error;
263  bool allow_file_access = false;
264  scoped_ptr<base::ListValue> value(set1.ToValue());
265  set2.Populate(*value, URLPattern::SCHEME_ALL, allow_file_access, &error);
266  EXPECT_EQ(set1, set2);
267
268  set2.ClearPatterns();
269  set2.Populate(patterns, URLPattern::SCHEME_ALL, allow_file_access, &error);
270  EXPECT_EQ(set1, set2);
271}
272
273TEST(URLPatternSetTest, NwayUnion) {
274  std::string google_a = "http://www.google.com/a*";
275  std::string google_b = "http://www.google.com/b*";
276  std::string google_c = "http://www.google.com/c*";
277  std::string yahoo_a = "http://www.yahoo.com/a*";
278  std::string yahoo_b = "http://www.yahoo.com/b*";
279  std::string yahoo_c = "http://www.yahoo.com/c*";
280  std::string reddit_a = "http://www.reddit.com/a*";
281  std::string reddit_b = "http://www.reddit.com/b*";
282  std::string reddit_c = "http://www.reddit.com/c*";
283
284  // Empty list.
285  {
286    std::vector<URLPatternSet> empty;
287
288    URLPatternSet result;
289    URLPatternSet::CreateUnion(empty, &result);
290
291    URLPatternSet expected;
292    EXPECT_EQ(expected, result);
293  }
294
295  // Singleton list.
296  {
297    std::vector<URLPatternSet> test;
298    test.push_back(Patterns(google_a));
299
300    URLPatternSet result;
301    URLPatternSet::CreateUnion(test, &result);
302
303    URLPatternSet expected = Patterns(google_a);
304    EXPECT_EQ(expected, result);
305  }
306
307  // List with 2 elements.
308  {
309    std::vector<URLPatternSet> test;
310    test.push_back(Patterns(google_a, google_b));
311    test.push_back(Patterns(google_b, google_c));
312
313    URLPatternSet result;
314    URLPatternSet::CreateUnion(test, &result);
315
316    URLPatternSet expected;
317    AddPattern(&expected, google_a);
318    AddPattern(&expected, google_b);
319    AddPattern(&expected, google_c);
320    EXPECT_EQ(expected, result);
321  }
322
323  // List with 3 elements.
324  {
325    std::vector<URLPatternSet> test;
326    test.push_back(Patterns(google_a, google_b));
327    test.push_back(Patterns(google_b, google_c));
328    test.push_back(Patterns(yahoo_a, yahoo_b));
329
330    URLPatternSet result;
331    URLPatternSet::CreateUnion(test, &result);
332
333    URLPatternSet expected;
334    AddPattern(&expected, google_a);
335    AddPattern(&expected, google_b);
336    AddPattern(&expected, google_c);
337    AddPattern(&expected, yahoo_a);
338    AddPattern(&expected, yahoo_b);
339    EXPECT_EQ(expected, result);
340  }
341
342  // List with 7 elements.
343  {
344    std::vector<URLPatternSet> test;
345    test.push_back(Patterns(google_a));
346    test.push_back(Patterns(google_b));
347    test.push_back(Patterns(google_c));
348    test.push_back(Patterns(yahoo_a));
349    test.push_back(Patterns(yahoo_b));
350    test.push_back(Patterns(yahoo_c));
351    test.push_back(Patterns(reddit_a));
352
353    URLPatternSet result;
354    URLPatternSet::CreateUnion(test, &result);
355
356    URLPatternSet expected;
357    AddPattern(&expected, google_a);
358    AddPattern(&expected, google_b);
359    AddPattern(&expected, google_c);
360    AddPattern(&expected, yahoo_a);
361    AddPattern(&expected, yahoo_b);
362    AddPattern(&expected, yahoo_c);
363    AddPattern(&expected, reddit_a);
364    EXPECT_EQ(expected, result);
365  }
366
367  // List with 8 elements.
368  {
369    std::vector<URLPatternSet> test;
370    test.push_back(Patterns(google_a));
371    test.push_back(Patterns(google_b));
372    test.push_back(Patterns(google_c));
373    test.push_back(Patterns(yahoo_a));
374    test.push_back(Patterns(yahoo_b));
375    test.push_back(Patterns(yahoo_c));
376    test.push_back(Patterns(reddit_a));
377    test.push_back(Patterns(reddit_b));
378
379    URLPatternSet result;
380    URLPatternSet::CreateUnion(test, &result);
381
382    URLPatternSet expected;
383    AddPattern(&expected, google_a);
384    AddPattern(&expected, google_b);
385    AddPattern(&expected, google_c);
386    AddPattern(&expected, yahoo_a);
387    AddPattern(&expected, yahoo_b);
388    AddPattern(&expected, yahoo_c);
389    AddPattern(&expected, reddit_a);
390    AddPattern(&expected, reddit_b);
391    EXPECT_EQ(expected, result);
392  }
393
394  // List with 9 elements.
395  {
396    std::vector<URLPatternSet> test;
397    test.push_back(Patterns(google_a));
398    test.push_back(Patterns(google_b));
399    test.push_back(Patterns(google_c));
400    test.push_back(Patterns(yahoo_a));
401    test.push_back(Patterns(yahoo_b));
402    test.push_back(Patterns(yahoo_c));
403    test.push_back(Patterns(reddit_a));
404    test.push_back(Patterns(reddit_b));
405    test.push_back(Patterns(reddit_c));
406
407    URLPatternSet result;
408    URLPatternSet::CreateUnion(test, &result);
409
410    URLPatternSet expected;
411    AddPattern(&expected, google_a);
412    AddPattern(&expected, google_b);
413    AddPattern(&expected, google_c);
414    AddPattern(&expected, yahoo_a);
415    AddPattern(&expected, yahoo_b);
416    AddPattern(&expected, yahoo_c);
417    AddPattern(&expected, reddit_a);
418    AddPattern(&expected, reddit_b);
419    AddPattern(&expected, reddit_c);
420    EXPECT_EQ(expected, result);
421  }
422}
423
424TEST(URLPatternSetTest, AddOrigin) {
425  URLPatternSet set;
426  EXPECT_TRUE(set.AddOrigin(
427      URLPattern::SCHEME_ALL, GURL("https://www.google.com/")));
428  EXPECT_TRUE(set.MatchesURL(GURL("https://www.google.com/foo/bar")));
429  EXPECT_FALSE(set.MatchesURL(GURL("http://www.google.com/foo/bar")));
430  EXPECT_FALSE(set.MatchesURL(GURL("https://en.google.com/foo/bar")));
431  set.ClearPatterns();
432
433  EXPECT_TRUE(set.AddOrigin(
434      URLPattern::SCHEME_ALL, GURL("https://google.com/")));
435  EXPECT_FALSE(set.MatchesURL(GURL("https://www.google.com/foo/bar")));
436  EXPECT_TRUE(set.MatchesURL(GURL("https://google.com/foo/bar")));
437
438  EXPECT_FALSE(set.AddOrigin(
439      URLPattern::SCHEME_HTTP, GURL("https://google.com/")));
440}
441
442}  // namespace extensions
443