Roll src/third_party/WebKit 605a979:06cb9e9 (svn 202556:202558)
[chromium-blink-merge.git] / components / url_matcher / url_matcher_factory_unittest.cc
blobc2fc71be4e23421bbd30f149b25365a7ef6b930a
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.
5 #include "components/url_matcher/url_matcher_factory.h"
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"
15 namespace url_matcher {
17 namespace keys = url_matcher_constants;
19 TEST(URLMatcherFactoryTest, CreateFromURLFilterDictionary) {
20 URLMatcher matcher;
22 std::string error;
23 scoped_refptr<URLMatcherConditionSet> result;
25 // Invalid key: {"invalid": "foobar"}
26 base::DictionaryValue invalid_condition;
27 invalid_condition.SetString("invalid", "foobar");
29 // Invalid value type: {"hostSuffix": []}
30 base::DictionaryValue invalid_condition2;
31 invalid_condition2.Set(keys::kHostSuffixKey, new base::ListValue);
33 // Invalid regex value: {"urlMatches": "*"}
34 base::DictionaryValue invalid_condition3;
35 invalid_condition3.SetString(keys::kURLMatchesKey, "*");
37 // Invalid regex value: {"originAndPathMatches": "*"}
38 base::DictionaryValue invalid_condition4;
39 invalid_condition4.SetString(keys::kOriginAndPathMatchesKey, "*");
41 // Valid values:
42 // {
43 // "port_range": [80, [1000, 1010]],
44 // "schemes": ["http"],
45 // "hostSuffix": "example.com"
46 // "hostPrefix": "www"
47 // }
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);
57 base::ListValue* scheme_list = new base::ListValue();
58 scheme_list->Append(new base::StringValue("http"));
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);
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());
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());
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());
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());
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());
100 URLMatcherConditionSet::Vector conditions;
101 conditions.push_back(result);
102 matcher.AddConditionSets(conditions);
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());
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;
122 // {"hostContains": "exaMple"}
123 base::DictionaryValue invalid_condition1;
124 invalid_condition1.SetString(keys::kHostContainsKey, "exaMple");
126 // {"hostSuffix": ".Com"}
127 base::DictionaryValue invalid_condition2;
128 invalid_condition2.SetString(keys::kHostSuffixKey, ".Com");
130 // {"hostPrefix": "WWw."}
131 base::DictionaryValue invalid_condition3;
132 invalid_condition3.SetString(keys::kHostPrefixKey, "WWw.");
134 // {"hostEquals": "WWW.example.Com"}
135 base::DictionaryValue invalid_condition4;
136 invalid_condition4.SetString(keys::kHostEqualsKey, "WWW.example.Com");
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);
144 const base::DictionaryValue* invalid_conditions[] = {
145 &invalid_condition1,
146 &invalid_condition2,
147 &invalid_condition3,
148 &invalid_condition4,
149 &invalid_condition5
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;
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) {}
183 ~UrlConditionCaseTest() {}
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;
190 private:
191 enum ResultType { OK, NOT_FULFILLED, CREATE_FAILURE };
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;
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;
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_;
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.
222 void UrlConditionCaseTest::Test() const {
223 CheckCondition(expected_value_, OK);
224 CheckCondition(incorrect_case_value_, expected_result_for_wrong_case_);
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);
239 URLMatcher matcher;
240 std::string error;
241 scoped_refptr<URLMatcherConditionSet> result;
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;
250 EXPECT_EQ("", error);
251 ASSERT_TRUE(result.get());
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_;
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;
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),
333 for (size_t i = 0; i < arraysize(case_tests); ++i) {
334 SCOPED_TRACE(base::StringPrintf("Iteration: %" PRIuS, i));
335 case_tests[i].Test();
339 } // namespace url_matcher