Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / components / url_matcher / url_matcher_factory_unittest.cc
1 // Copyright 2013 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 "components/url_matcher/url_matcher_factory.h"
6
7 #include "base/basictypes.h"
8 #include "base/format_macros.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/values.h"
11 #include "components/url_matcher/url_matcher_constants.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "url/gurl.h"
14
15 namespace url_matcher {
16
17 namespace keys = url_matcher_constants;
18
19 TEST(URLMatcherFactoryTest, CreateFromURLFilterDictionary) {
20   URLMatcher matcher;
21
22   std::string error;
23   scoped_refptr<URLMatcherConditionSet> result;
24
25   // Invalid key: {"invalid": "foobar"}
26   base::DictionaryValue invalid_condition;
27   invalid_condition.SetString("invalid", "foobar");
28
29   // Invalid value type: {"hostSuffix": []}
30   base::DictionaryValue invalid_condition2;
31   invalid_condition2.Set(keys::kHostSuffixKey, new base::ListValue);
32
33   // Invalid regex value: {"urlMatches": "*"}
34   base::DictionaryValue invalid_condition3;
35   invalid_condition3.SetString(keys::kURLMatchesKey, "*");
36
37   // Invalid regex value: {"originAndPathMatches": "*"}
38   base::DictionaryValue invalid_condition4;
39   invalid_condition4.SetString(keys::kOriginAndPathMatchesKey, "*");
40
41   // Valid values:
42   // {
43   //   "port_range": [80, [1000, 1010]],
44   //   "schemes": ["http"],
45   //   "hostSuffix": "example.com"
46   //   "hostPrefix": "www"
47   // }
48
49   // Port range: Allow 80;1000-1010.
50   base::ListValue* port_range = new base::ListValue();
51   port_range->Append(new base::FundamentalValue(1000));
52   port_range->Append(new base::FundamentalValue(1010));
53   base::ListValue* port_ranges = new base::ListValue();
54   port_ranges->Append(new base::FundamentalValue(80));
55   port_ranges->Append(port_range);
56
57   base::ListValue* scheme_list = new base::ListValue();
58   scheme_list->Append(new base::StringValue("http"));
59
60   base::DictionaryValue valid_condition;
61   valid_condition.SetString(keys::kHostSuffixKey, "example.com");
62   valid_condition.SetString(keys::kHostPrefixKey, "www");
63   valid_condition.Set(keys::kPortsKey, port_ranges);
64   valid_condition.Set(keys::kSchemesKey, scheme_list);
65
66   // Test wrong condition name passed.
67   error.clear();
68   result = URLMatcherFactory::CreateFromURLFilterDictionary(
69       matcher.condition_factory(), &invalid_condition, 1, &error);
70   EXPECT_FALSE(error.empty());
71   EXPECT_FALSE(result.get());
72
73   // Test wrong datatype in hostSuffix.
74   error.clear();
75   result = URLMatcherFactory::CreateFromURLFilterDictionary(
76       matcher.condition_factory(), &invalid_condition2, 2, &error);
77   EXPECT_FALSE(error.empty());
78   EXPECT_FALSE(result.get());
79
80   // Test invalid regex in urlMatches.
81   error.clear();
82   result = URLMatcherFactory::CreateFromURLFilterDictionary(
83       matcher.condition_factory(), &invalid_condition3, 3, &error);
84   EXPECT_FALSE(error.empty());
85   EXPECT_FALSE(result.get());
86
87   error.clear();
88   result = URLMatcherFactory::CreateFromURLFilterDictionary(
89       matcher.condition_factory(), &invalid_condition4, 4, &error);
90   EXPECT_FALSE(error.empty());
91   EXPECT_FALSE(result.get());
92
93   // Test success.
94   error.clear();
95   result = URLMatcherFactory::CreateFromURLFilterDictionary(
96       matcher.condition_factory(), &valid_condition, 100, &error);
97   EXPECT_EQ("", error);
98   ASSERT_TRUE(result.get());
99
100   URLMatcherConditionSet::Vector conditions;
101   conditions.push_back(result);
102   matcher.AddConditionSets(conditions);
103
104   EXPECT_EQ(1u, matcher.MatchURL(GURL("http://www.example.com")).size());
105   EXPECT_EQ(1u, matcher.MatchURL(GURL("http://www.example.com:80")).size());
106   EXPECT_EQ(1u, matcher.MatchURL(GURL("http://www.example.com:1000")).size());
107   // Wrong scheme.
108   EXPECT_EQ(0u, matcher.MatchURL(GURL("https://www.example.com:80")).size());
109   // Wrong port.
110   EXPECT_EQ(0u, matcher.MatchURL(GURL("http://www.example.com:81")).size());
111   // Unfulfilled host prefix.
112   EXPECT_EQ(0u, matcher.MatchURL(GURL("http://mail.example.com:81")).size());
113 }
114
115 // Using upper case letters for scheme and host values is currently an error.
116 // See more context at http://crbug.com/160702#c6 .
117 TEST(URLMatcherFactoryTest, UpperCase) {
118   URLMatcher matcher;
119   std::string error;
120   scoped_refptr<URLMatcherConditionSet> result;
121
122   // {"hostContains": "exaMple"}
123   base::DictionaryValue invalid_condition1;
124   invalid_condition1.SetString(keys::kHostContainsKey, "exaMple");
125
126   // {"hostSuffix": ".Com"}
127   base::DictionaryValue invalid_condition2;
128   invalid_condition2.SetString(keys::kHostSuffixKey, ".Com");
129
130   // {"hostPrefix": "WWw."}
131   base::DictionaryValue invalid_condition3;
132   invalid_condition3.SetString(keys::kHostPrefixKey, "WWw.");
133
134   // {"hostEquals": "WWW.example.Com"}
135   base::DictionaryValue invalid_condition4;
136   invalid_condition4.SetString(keys::kHostEqualsKey, "WWW.example.Com");
137
138   // {"scheme": ["HTTP"]}
139   base::ListValue* scheme_list = new base::ListValue();
140   scheme_list->Append(new base::StringValue("HTTP"));
141   base::DictionaryValue invalid_condition5;
142   invalid_condition5.Set(keys::kSchemesKey, scheme_list);
143
144   const base::DictionaryValue* invalid_conditions[] = {
145     &invalid_condition1,
146     &invalid_condition2,
147     &invalid_condition3,
148     &invalid_condition4,
149     &invalid_condition5
150   };
151
152   for (size_t i = 0; i < arraysize(invalid_conditions); ++i) {
153     error.clear();
154     result = URLMatcherFactory::CreateFromURLFilterDictionary(
155         matcher.condition_factory(), invalid_conditions[i], 1, &error);
156     EXPECT_FALSE(error.empty()) << "in iteration " << i;
157     EXPECT_FALSE(result.get()) << "in iteration " << i;
158   }
159 }
160
161 // This class wraps a case sensitivity test for a single UrlFilter condition.
162 class UrlConditionCaseTest {
163  public:
164   // The condition is identified by the key |condition_key|. If that key is
165   // associated with string values, then |use_list_of_strings| should be false,
166   // if the key is associated with list-of-string values, then
167   // |use_list_of_strings| should be true. In |url| is the URL to test against.
168   UrlConditionCaseTest(const char* condition_key,
169                        bool use_list_of_strings,
170                        const std::string& expected_value,
171                        const std::string& incorrect_case_value,
172                        bool case_sensitive,
173                        bool lower_case_enforced,
174                        const GURL& url)
175       : condition_key_(condition_key),
176         use_list_of_strings_(use_list_of_strings),
177         expected_value_(expected_value),
178         incorrect_case_value_(incorrect_case_value),
179         expected_result_for_wrong_case_(ExpectedResult(case_sensitive,
180                                                        lower_case_enforced)),
181         url_(url) {}
182
183   ~UrlConditionCaseTest() {}
184
185   // Match the condition against |url_|. Checks via EXPECT_* macros that
186   // |expected_value_| matches always, and that |incorrect_case_value_| matches
187   // iff |case_sensitive_| is false.
188   void Test() const;
189
190  private:
191   enum ResultType { OK, NOT_FULFILLED, CREATE_FAILURE };
192
193   // What is the expected result of |CheckCondition| if a wrong-case |value|
194   // containing upper case letters is supplied.
195   static ResultType ExpectedResult(bool case_sensitive,
196                                    bool lower_case_enforced) {
197     if (lower_case_enforced)
198       return CREATE_FAILURE;
199     if (case_sensitive)
200       return NOT_FULFILLED;
201     return OK;
202   }
203
204   // Test the condition |condition_key_| = |value| against |url_|.
205   // Check, via EXPECT_* macros, that either the condition cannot be constructed
206   // at all, or that the condition is not fulfilled, or that it is fulfilled,
207   // depending on the value of |expected_result|.
208   void CheckCondition(const std::string& value,
209                       ResultType expected_result) const;
210
211   const char* condition_key_;
212   const bool use_list_of_strings_;
213   const std::string& expected_value_;
214   const std::string& incorrect_case_value_;
215   const ResultType expected_result_for_wrong_case_;
216   const GURL& url_;
217
218   // Allow implicit copy and assign, because a public copy constructor is
219   // needed, but never used (!), for the definition of arrays of this class.
220 };
221
222 void UrlConditionCaseTest::Test() const {
223   CheckCondition(expected_value_, OK);
224   CheckCondition(incorrect_case_value_, expected_result_for_wrong_case_);
225 }
226
227 void UrlConditionCaseTest::CheckCondition(
228     const std::string& value,
229     UrlConditionCaseTest::ResultType expected_result) const {
230   base::DictionaryValue condition;
231   if (use_list_of_strings_) {
232     base::ListValue* list = new base::ListValue();
233     list->Append(new base::StringValue(value));
234     condition.SetWithoutPathExpansion(condition_key_, list);
235   } else {
236     condition.SetStringWithoutPathExpansion(condition_key_, value);
237   }
238
239   URLMatcher matcher;
240   std::string error;
241   scoped_refptr<URLMatcherConditionSet> result;
242
243   result = URLMatcherFactory::CreateFromURLFilterDictionary(
244       matcher.condition_factory(), &condition, 1, &error);
245   if (expected_result == CREATE_FAILURE) {
246     EXPECT_FALSE(error.empty());
247     EXPECT_FALSE(result.get());
248     return;
249   }
250   EXPECT_EQ("", error);
251   ASSERT_TRUE(result.get());
252
253   URLMatcherConditionSet::Vector conditions;
254   conditions.push_back(result);
255   matcher.AddConditionSets(conditions);
256   EXPECT_EQ((expected_result == OK ? 1u : 0u), matcher.MatchURL(url_).size())
257       << "while matching condition " << condition_key_ << " with value "
258       << value  << " against url " << url_;
259 }
260
261 // This tests that the UrlFilter handles case sensitivity on various parts of
262 // URLs correctly.
263 TEST(URLMatcherFactoryTest, CaseSensitivity) {
264   const std::string kScheme("https");
265   const std::string kSchemeUpper("HTTPS");
266   const std::string kHost("www.example.com");
267   const std::string kHostUpper("WWW.EXAMPLE.COM");
268   const std::string kPath("/path");
269   const std::string kPathUpper("/PATH");
270   const std::string kQuery("?option=value&A=B");
271   const std::string kQueryUpper("?OPTION=VALUE&A=B");
272   const std::string kUrl(kScheme + "://" + kHost + ":1234" + kPath + kQuery);
273   const std::string kUrlUpper(
274       kSchemeUpper + "://" + kHostUpper + ":1234" + kPathUpper + kQueryUpper);
275   const GURL url(kUrl);
276   // Note: according to RFC 3986, and RFC 1034, schema and host, respectively
277   // should be case insensitive. See crbug.com/160702#6 for why we still
278   // require them to be case sensitive in UrlFilter, and enforce lower case.
279   const bool kIsSchemeLowerCaseEnforced = true;
280   const bool kIsHostLowerCaseEnforced = true;
281   const bool kIsPathLowerCaseEnforced = false;
282   const bool kIsQueryLowerCaseEnforced = false;
283   const bool kIsUrlLowerCaseEnforced = false;
284   const bool kIsSchemeCaseSensitive = true;
285   const bool kIsHostCaseSensitive = true;
286   const bool kIsPathCaseSensitive = true;
287   const bool kIsQueryCaseSensitive = true;
288   const bool kIsUrlCaseSensitive = kIsSchemeCaseSensitive ||
289                                    kIsHostCaseSensitive ||
290                                    kIsPathCaseSensitive ||
291                                    kIsQueryCaseSensitive;
292
293   const UrlConditionCaseTest case_tests[] = {
294     UrlConditionCaseTest(keys::kSchemesKey, true, kScheme, kSchemeUpper,
295                          kIsSchemeCaseSensitive, kIsSchemeLowerCaseEnforced,
296                          url),
297     UrlConditionCaseTest(keys::kHostContainsKey, false, kHost, kHostUpper,
298                          kIsHostCaseSensitive, kIsHostLowerCaseEnforced, url),
299     UrlConditionCaseTest(keys::kHostEqualsKey, false, kHost, kHostUpper,
300                          kIsHostCaseSensitive, kIsHostLowerCaseEnforced, url),
301     UrlConditionCaseTest(keys::kHostPrefixKey, false, kHost, kHostUpper,
302                          kIsHostCaseSensitive, kIsHostLowerCaseEnforced, url),
303     UrlConditionCaseTest(keys::kHostSuffixKey, false, kHost, kHostUpper,
304                          kIsHostCaseSensitive, kIsHostLowerCaseEnforced, url),
305     UrlConditionCaseTest(keys::kPathContainsKey, false, kPath, kPathUpper,
306                          kIsPathCaseSensitive, kIsPathLowerCaseEnforced, url),
307     UrlConditionCaseTest(keys::kPathEqualsKey, false, kPath, kPathUpper,
308                          kIsPathCaseSensitive, kIsPathLowerCaseEnforced, url),
309     UrlConditionCaseTest(keys::kPathPrefixKey, false, kPath, kPathUpper,
310                          kIsPathCaseSensitive, kIsPathLowerCaseEnforced, url),
311     UrlConditionCaseTest(keys::kPathSuffixKey, false, kPath, kPathUpper,
312                          kIsPathCaseSensitive, kIsPathLowerCaseEnforced, url),
313     UrlConditionCaseTest(keys::kQueryContainsKey, false, kQuery, kQueryUpper,
314                          kIsQueryCaseSensitive, kIsQueryLowerCaseEnforced, url),
315     UrlConditionCaseTest(keys::kQueryEqualsKey, false, kQuery, kQueryUpper,
316                          kIsQueryCaseSensitive, kIsQueryLowerCaseEnforced, url),
317     UrlConditionCaseTest(keys::kQueryPrefixKey, false, kQuery, kQueryUpper,
318                          kIsQueryCaseSensitive, kIsQueryLowerCaseEnforced, url),
319     UrlConditionCaseTest(keys::kQuerySuffixKey, false, kQuery, kQueryUpper,
320                          kIsQueryCaseSensitive, kIsQueryLowerCaseEnforced, url),
321     // Excluding kURLMatchesKey because case sensitivity can be specified in the
322     // RE2 expression.
323     UrlConditionCaseTest(keys::kURLContainsKey, false, kUrl, kUrlUpper,
324                          kIsUrlCaseSensitive, kIsUrlLowerCaseEnforced, url),
325     UrlConditionCaseTest(keys::kURLEqualsKey, false, kUrl, kUrlUpper,
326                          kIsUrlCaseSensitive, kIsUrlLowerCaseEnforced, url),
327     UrlConditionCaseTest(keys::kURLPrefixKey, false, kUrl, kUrlUpper,
328                          kIsUrlCaseSensitive, kIsUrlLowerCaseEnforced, url),
329     UrlConditionCaseTest(keys::kURLSuffixKey, false, kUrl, kUrlUpper,
330                          kIsUrlCaseSensitive, kIsUrlLowerCaseEnforced, url),
331   };
332
333   for (size_t i = 0; i < arraysize(case_tests); ++i) {
334     SCOPED_TRACE(base::StringPrintf("Iteration: %" PRIuS, i));
335     case_tests[i].Test();
336   }
337 }
338
339 }  // namespace url_matcher