Update {virtual,override,final} to follow C++11 style.
[chromium-blink-merge.git] / extensions / browser / api / declarative_webrequest / webrequest_condition_attribute_unittest.cc
blob13b7298c0fbf1610471d0f1b77317d7087511d68
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.
5 #include "extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.h"
7 #include "base/basictypes.h"
8 #include "base/files/file_path.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/values.h"
12 #include "content/public/browser/resource_request_info.h"
13 #include "extensions/browser/api/declarative_webrequest/webrequest_condition.h"
14 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
15 #include "net/base/request_priority.h"
16 #include "net/test/embedded_test_server/embedded_test_server.h"
17 #include "net/url_request/url_request.h"
18 #include "net/url_request/url_request_test_util.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 using base::DictionaryValue;
22 using base::FundamentalValue;
23 using base::ListValue;
24 using base::StringValue;
25 using base::Value;
26 using content::ResourceType;
28 namespace extensions {
30 namespace keys = declarative_webrequest_constants;
32 namespace {
33 const char kUnknownConditionName[] = "unknownType";
35 base::FilePath TestDataPath(base::StringPiece relative_to_src) {
36 base::FilePath src_dir;
37 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
38 return src_dir.AppendASCII(relative_to_src);
41 TEST(WebRequestConditionAttributeTest, CreateConditionAttribute) {
42 // Necessary for TestURLRequest.
43 base::MessageLoopForIO message_loop;
45 std::string error;
46 scoped_refptr<const WebRequestConditionAttribute> result;
47 base::StringValue string_value("main_frame");
48 base::ListValue resource_types;
49 resource_types.Append(new base::StringValue("main_frame"));
51 // Test wrong condition name passed.
52 error.clear();
53 result = WebRequestConditionAttribute::Create(
54 kUnknownConditionName, &resource_types, &error);
55 EXPECT_FALSE(error.empty());
56 EXPECT_FALSE(result.get());
58 // Test wrong data type passed
59 error.clear();
60 result = WebRequestConditionAttribute::Create(
61 keys::kResourceTypeKey, &string_value, &error);
62 EXPECT_FALSE(error.empty());
63 EXPECT_FALSE(result.get());
65 error.clear();
66 result = WebRequestConditionAttribute::Create(
67 keys::kContentTypeKey, &string_value, &error);
68 EXPECT_FALSE(error.empty());
69 EXPECT_FALSE(result.get());
71 // Test success
72 error.clear();
73 result = WebRequestConditionAttribute::Create(
74 keys::kResourceTypeKey, &resource_types, &error);
75 EXPECT_EQ("", error);
76 ASSERT_TRUE(result.get());
77 EXPECT_EQ(WebRequestConditionAttribute::CONDITION_RESOURCE_TYPE,
78 result->GetType());
79 EXPECT_EQ(std::string(keys::kResourceTypeKey), result->GetName());
82 TEST(WebRequestConditionAttributeTest, ResourceType) {
83 // Necessary for TestURLRequest.
84 base::MessageLoopForIO message_loop;
86 std::string error;
87 base::ListValue resource_types;
88 // The 'sub_frame' value is chosen arbitrarily, so as the corresponding
89 // content::ResourceType is not 0, the default value.
90 resource_types.Append(new base::StringValue("sub_frame"));
92 scoped_refptr<const WebRequestConditionAttribute> attribute =
93 WebRequestConditionAttribute::Create(
94 keys::kResourceTypeKey, &resource_types, &error);
95 EXPECT_EQ("", error);
96 ASSERT_TRUE(attribute.get());
97 EXPECT_EQ(std::string(keys::kResourceTypeKey), attribute->GetName());
99 net::TestURLRequestContext context;
100 scoped_ptr<net::URLRequest> url_request_ok(context.CreateRequest(
101 GURL("http://www.example.com"), net::DEFAULT_PRIORITY, NULL, NULL));
102 content::ResourceRequestInfo::AllocateForTesting(
103 url_request_ok.get(),
104 content::RESOURCE_TYPE_SUB_FRAME,
105 NULL, // context
106 -1, // render_process_id
107 -1, // render_view_id
108 -1, // render_frame_id
109 false, // is_main_frame
110 false, // parent_is_main_frame
111 true, // allow_download
112 false); // is_async
113 EXPECT_TRUE(attribute->IsFulfilled(WebRequestData(url_request_ok.get(),
114 ON_BEFORE_REQUEST)));
116 scoped_ptr<net::URLRequest> url_request_fail(context.CreateRequest(
117 GURL("http://www.example.com"), net::DEFAULT_PRIORITY, NULL, NULL));
118 content::ResourceRequestInfo::AllocateForTesting(
119 url_request_fail.get(),
120 content::RESOURCE_TYPE_MAIN_FRAME,
121 NULL, // context
122 -1, // render_process_id
123 -1, // render_view_id
124 -1, // render_frame_id
125 true, // is_main_frame
126 false, // parent_is_main_frame
127 true, // allow_download
128 false); // is_async
129 EXPECT_FALSE(attribute->IsFulfilled(WebRequestData(url_request_fail.get(),
130 ON_BEFORE_REQUEST)));
133 TEST(WebRequestConditionAttributeTest, ContentType) {
134 // Necessary for TestURLRequest.
135 base::MessageLoopForIO message_loop;
137 std::string error;
138 scoped_refptr<const WebRequestConditionAttribute> result;
140 net::test_server::EmbeddedTestServer test_server;
141 test_server.ServeFilesFromDirectory(TestDataPath(
142 "chrome/test/data/extensions/api_test/webrequest/declarative"));
143 ASSERT_TRUE(test_server.InitializeAndWaitUntilReady());
145 net::TestURLRequestContext context;
146 net::TestDelegate delegate;
147 scoped_ptr<net::URLRequest> url_request(
148 context.CreateRequest(test_server.GetURL("/headers.html"),
149 net::DEFAULT_PRIORITY,
150 &delegate,
151 NULL));
152 url_request->Start();
153 base::MessageLoop::current()->Run();
155 base::ListValue content_types;
156 content_types.Append(new base::StringValue("text/plain"));
157 scoped_refptr<const WebRequestConditionAttribute> attribute_include =
158 WebRequestConditionAttribute::Create(
159 keys::kContentTypeKey, &content_types, &error);
160 EXPECT_EQ("", error);
161 ASSERT_TRUE(attribute_include.get());
162 EXPECT_FALSE(attribute_include->IsFulfilled(
163 WebRequestData(url_request.get(), ON_BEFORE_REQUEST,
164 url_request->response_headers())));
165 EXPECT_TRUE(attribute_include->IsFulfilled(
166 WebRequestData(url_request.get(), ON_HEADERS_RECEIVED,
167 url_request->response_headers())));
168 EXPECT_EQ(std::string(keys::kContentTypeKey), attribute_include->GetName());
170 scoped_refptr<const WebRequestConditionAttribute> attribute_exclude =
171 WebRequestConditionAttribute::Create(
172 keys::kExcludeContentTypeKey, &content_types, &error);
173 EXPECT_EQ("", error);
174 ASSERT_TRUE(attribute_exclude.get());
175 EXPECT_FALSE(attribute_exclude->IsFulfilled(
176 WebRequestData(url_request.get(), ON_HEADERS_RECEIVED,
177 url_request->response_headers())));
179 content_types.Clear();
180 content_types.Append(new base::StringValue("something/invalid"));
181 scoped_refptr<const WebRequestConditionAttribute> attribute_unincluded =
182 WebRequestConditionAttribute::Create(
183 keys::kContentTypeKey, &content_types, &error);
184 EXPECT_EQ("", error);
185 ASSERT_TRUE(attribute_unincluded.get());
186 EXPECT_FALSE(attribute_unincluded->IsFulfilled(
187 WebRequestData(url_request.get(), ON_HEADERS_RECEIVED,
188 url_request->response_headers())));
190 scoped_refptr<const WebRequestConditionAttribute> attribute_unexcluded =
191 WebRequestConditionAttribute::Create(
192 keys::kExcludeContentTypeKey, &content_types, &error);
193 EXPECT_EQ("", error);
194 ASSERT_TRUE(attribute_unexcluded.get());
195 EXPECT_TRUE(attribute_unexcluded->IsFulfilled(
196 WebRequestData(url_request.get(), ON_HEADERS_RECEIVED,
197 url_request->response_headers())));
198 EXPECT_EQ(std::string(keys::kExcludeContentTypeKey),
199 attribute_unexcluded->GetName());
202 // Testing WebRequestConditionAttributeThirdParty.
203 TEST(WebRequestConditionAttributeTest, ThirdParty) {
204 // Necessary for TestURLRequest.
205 base::MessageLoopForIO message_loop;
207 std::string error;
208 const FundamentalValue value_true(true);
209 // This attribute matches only third party requests.
210 scoped_refptr<const WebRequestConditionAttribute> third_party_attribute =
211 WebRequestConditionAttribute::Create(keys::kThirdPartyKey,
212 &value_true,
213 &error);
214 ASSERT_EQ("", error);
215 ASSERT_TRUE(third_party_attribute.get());
216 EXPECT_EQ(std::string(keys::kThirdPartyKey),
217 third_party_attribute->GetName());
218 const FundamentalValue value_false(false);
219 // This attribute matches only first party requests.
220 scoped_refptr<const WebRequestConditionAttribute> first_party_attribute =
221 WebRequestConditionAttribute::Create(keys::kThirdPartyKey,
222 &value_false,
223 &error);
224 ASSERT_EQ("", error);
225 ASSERT_TRUE(first_party_attribute.get());
226 EXPECT_EQ(std::string(keys::kThirdPartyKey),
227 first_party_attribute->GetName());
229 const GURL url_empty;
230 const GURL url_a("http://a.com");
231 const GURL url_b("http://b.com");
232 net::TestURLRequestContext context;
233 net::TestDelegate delegate;
234 scoped_ptr<net::URLRequest> url_request(
235 context.CreateRequest(url_a, net::DEFAULT_PRIORITY, &delegate, NULL));
237 for (unsigned int i = 1; i <= kLastActiveStage; i <<= 1) {
238 if (!(kActiveStages & i))
239 continue;
240 const RequestStage stage = static_cast<RequestStage>(i);
241 url_request->set_first_party_for_cookies(url_empty);
242 EXPECT_FALSE(third_party_attribute->IsFulfilled(
243 WebRequestData(url_request.get(), stage)));
244 EXPECT_TRUE(first_party_attribute->IsFulfilled(
245 WebRequestData(url_request.get(), stage)));
247 url_request->set_first_party_for_cookies(url_b);
248 EXPECT_TRUE(third_party_attribute->IsFulfilled(
249 WebRequestData(url_request.get(), stage)));
250 EXPECT_FALSE(first_party_attribute->IsFulfilled(
251 WebRequestData(url_request.get(), stage)));
253 url_request->set_first_party_for_cookies(url_a);
254 EXPECT_FALSE(third_party_attribute->IsFulfilled(
255 WebRequestData(url_request.get(), stage)));
256 EXPECT_TRUE(first_party_attribute->IsFulfilled(
257 WebRequestData(url_request.get(), stage)));
261 // Testing WebRequestConditionAttributeStages. This iterates over all stages,
262 // and tests a couple of "stage" attributes -- one created with an empty set of
263 // applicable stages, one for each stage applicable for that stage, and one
264 // applicable in all stages.
265 TEST(WebRequestConditionAttributeTest, Stages) {
266 // Necessary for TestURLRequest.
267 base::MessageLoopForIO message_loop;
269 typedef std::pair<RequestStage, const char*> StageNamePair;
270 static const StageNamePair active_stages[] = {
271 StageNamePair(ON_BEFORE_REQUEST, keys::kOnBeforeRequestEnum),
272 StageNamePair(ON_BEFORE_SEND_HEADERS, keys::kOnBeforeSendHeadersEnum),
273 StageNamePair(ON_HEADERS_RECEIVED, keys::kOnHeadersReceivedEnum),
274 StageNamePair(ON_AUTH_REQUIRED, keys::kOnAuthRequiredEnum)
277 // Check that exactly all active stages are considered in this test.
278 unsigned int covered_stages = 0;
279 for (size_t i = 0; i < arraysize(active_stages); ++i)
280 covered_stages |= active_stages[i].first;
281 EXPECT_EQ(kActiveStages, covered_stages);
283 std::string error;
285 // Create an attribute with an empty set of applicable stages.
286 base::ListValue empty_list;
287 scoped_refptr<const WebRequestConditionAttribute> empty_attribute =
288 WebRequestConditionAttribute::Create(keys::kStagesKey,
289 &empty_list,
290 &error);
291 EXPECT_EQ("", error);
292 ASSERT_TRUE(empty_attribute.get());
293 EXPECT_EQ(std::string(keys::kStagesKey), empty_attribute->GetName());
295 // Create an attribute with all possible applicable stages.
296 base::ListValue all_stages;
297 for (size_t i = 0; i < arraysize(active_stages); ++i)
298 all_stages.AppendString(active_stages[i].second);
299 scoped_refptr<const WebRequestConditionAttribute> attribute_with_all =
300 WebRequestConditionAttribute::Create(keys::kStagesKey,
301 &all_stages,
302 &error);
303 EXPECT_EQ("", error);
304 ASSERT_TRUE(attribute_with_all.get());
305 EXPECT_EQ(std::string(keys::kStagesKey), attribute_with_all->GetName());
307 // Create one attribute for each single stage, to be applicable in that stage.
308 std::vector<scoped_refptr<const WebRequestConditionAttribute> >
309 one_stage_attributes;
311 for (size_t i = 0; i < arraysize(active_stages); ++i) {
312 base::ListValue single_stage_list;
313 single_stage_list.AppendString(active_stages[i].second);
314 one_stage_attributes.push_back(
315 WebRequestConditionAttribute::Create(keys::kStagesKey,
316 &single_stage_list,
317 &error));
318 EXPECT_EQ("", error);
319 ASSERT_TRUE(one_stage_attributes.back().get() != NULL);
322 const GURL url_empty;
323 net::TestURLRequestContext context;
324 net::TestDelegate delegate;
325 scoped_ptr<net::URLRequest> url_request(
326 context.CreateRequest(url_empty, net::DEFAULT_PRIORITY, &delegate, NULL));
328 for (size_t i = 0; i < arraysize(active_stages); ++i) {
329 EXPECT_FALSE(empty_attribute->IsFulfilled(
330 WebRequestData(url_request.get(), active_stages[i].first)));
332 for (size_t j = 0; j < one_stage_attributes.size(); ++j) {
333 EXPECT_EQ(i == j,
334 one_stage_attributes[j]->IsFulfilled(
335 WebRequestData(url_request.get(), active_stages[i].first)));
338 EXPECT_TRUE(attribute_with_all->IsFulfilled(
339 WebRequestData(url_request.get(), active_stages[i].first)));
343 namespace {
345 // Builds a vector of vectors of string pointers from an array of strings.
346 // |array| is in fact a sequence of arrays. The array |sizes| captures the sizes
347 // of all parts of |array|, and |size| is the length of |sizes| itself.
348 // Example (this is pseudo-code, not C++):
349 // array = { "a", "b", "c", "d", "e", "f" }
350 // sizes = { 2, 0, 4 }
351 // size = 3
352 // results in out == { {&"a", &"b"}, {}, {&"c", &"d", &"e", &"f"} }
353 void GetArrayAsVector(const std::string array[],
354 const size_t sizes[],
355 const size_t size,
356 std::vector< std::vector<const std::string*> >* out) {
357 out->clear();
358 size_t next = 0;
359 for (size_t i = 0; i < size; ++i) {
360 out->push_back(std::vector<const std::string*>());
361 for (size_t j = next; j < next + sizes[i]; ++j) {
362 out->back().push_back(&(array[j]));
364 next += sizes[i];
368 // Builds a DictionaryValue from an array of the form {name1, value1, name2,
369 // value2, ...}. Values for the same key are grouped in a ListValue.
370 scoped_ptr<base::DictionaryValue> GetDictionaryFromArray(
371 const std::vector<const std::string*>& array) {
372 const size_t length = array.size();
373 CHECK(length % 2 == 0);
375 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue);
376 for (size_t i = 0; i < length; i += 2) {
377 const std::string* name = array[i];
378 const std::string* value = array[i+1];
379 if (dictionary->HasKey(*name)) {
380 base::Value* entry = NULL;
381 scoped_ptr<base::Value> entry_owned;
382 base::ListValue* list = NULL;
383 if (!dictionary->GetWithoutPathExpansion(*name, &entry))
384 return scoped_ptr<base::DictionaryValue>();
385 switch (entry->GetType()) {
386 case base::Value::TYPE_STRING:
387 // Replace the present string with a list.
388 list = new base::ListValue;
389 // Ignoring return value, we already verified the entry is there.
390 dictionary->RemoveWithoutPathExpansion(*name, &entry_owned);
391 list->Append(entry_owned.release());
392 list->Append(new base::StringValue(*value));
393 dictionary->SetWithoutPathExpansion(*name, list);
394 break;
395 case base::Value::TYPE_LIST: // Just append to the list.
396 CHECK(entry->GetAsList(&list));
397 list->Append(new base::StringValue(*value));
398 break;
399 default:
400 NOTREACHED(); // We never put other Values here.
401 return scoped_ptr<base::DictionaryValue>();
403 } else {
404 dictionary->SetString(*name, *value);
407 return dictionary.Pass();
410 // Returns whether the response headers from |url_request| satisfy the match
411 // criteria given in |tests|. For at least one |i| all tests from |tests[i]|
412 // must pass. If |positive_test| is true, the dictionary is interpreted as the
413 // containsHeaders property of a RequestMatcher, otherwise as
414 // doesNotContainHeaders.
415 void MatchAndCheck(const std::vector< std::vector<const std::string*> >& tests,
416 const std::string& key,
417 RequestStage stage,
418 net::URLRequest* url_request,
419 bool* result) {
420 base::ListValue contains_headers;
421 for (size_t i = 0; i < tests.size(); ++i) {
422 scoped_ptr<base::DictionaryValue> temp(GetDictionaryFromArray(tests[i]));
423 ASSERT_TRUE(temp.get());
424 contains_headers.Append(temp.release());
427 std::string error;
428 scoped_refptr<const WebRequestConditionAttribute> attribute =
429 WebRequestConditionAttribute::Create(key, &contains_headers, &error);
430 ASSERT_EQ("", error);
431 ASSERT_TRUE(attribute.get());
432 EXPECT_EQ(key, attribute->GetName());
434 *result = attribute->IsFulfilled(WebRequestData(
435 url_request, stage, url_request->response_headers()));
438 } // namespace
440 // Here we test WebRequestConditionAttributeRequestHeaders for matching
441 // correctly against request headers. This test is not as extensive as
442 // "ResponseHeaders" (below), because the header-matching code is shared
443 // by both types of condition attributes, so it is enough to test it once.
444 TEST(WebRequestConditionAttributeTest, RequestHeaders) {
445 // Necessary for TestURLRequest.
446 base::MessageLoopForIO message_loop;
448 net::TestURLRequestContext context;
449 net::TestDelegate delegate;
450 scoped_ptr<net::URLRequest> url_request(
451 context.CreateRequest(GURL("http://example.com"), // Dummy URL.
452 net::DEFAULT_PRIORITY,
453 &delegate,
454 NULL));
455 url_request->SetExtraRequestHeaderByName(
456 "Custom-header", "custom/value", true /* overwrite */);
457 url_request->Start();
458 base::MessageLoop::current()->Run();
460 std::vector<std::vector<const std::string*> > tests;
461 bool result = false;
463 const RequestStage stage = ON_BEFORE_SEND_HEADERS;
465 // First set of test data -- passing conjunction.
466 const std::string kPassingCondition[] = {
467 keys::kNameContainsKey, "CuStOm", // Header names are case insensitive.
468 keys::kNameEqualsKey, "custom-header",
469 keys::kValueSuffixKey, "alue",
470 keys::kValuePrefixKey, "custom/value"
472 const size_t kPassingConditionSizes[] = { arraysize(kPassingCondition) };
473 GetArrayAsVector(kPassingCondition, kPassingConditionSizes, 1u, &tests);
474 // Positive filter, passing (conjunction of tests).
475 MatchAndCheck(
476 tests, keys::kRequestHeadersKey, stage, url_request.get(), &result);
477 EXPECT_TRUE(result);
478 // Negative filter, failing (conjunction of tests).
479 MatchAndCheck(tests, keys::kExcludeRequestHeadersKey, stage,
480 url_request.get(), &result);
481 EXPECT_FALSE(result);
483 // Second set of test data -- failing disjunction.
484 const std::string kFailCondition[] = {
485 keys::kNameSuffixKey, "Custom", // Test 1.
486 keys::kNameEqualsKey, "ustom-valu", // Test 2.
487 keys::kValuePrefixKey, "custom ", // Test 3.
488 keys::kValueContainsKey, " value" // Test 4.
490 const size_t kFailConditionSizes[] = { 2u, 2u, 2u, 2u };
491 GetArrayAsVector(kFailCondition, kFailConditionSizes, 4u, &tests);
492 // Positive filter, failing (disjunction of tests).
493 MatchAndCheck(tests, keys::kRequestHeadersKey, stage, url_request.get(),
494 &result);
495 EXPECT_FALSE(result);
496 // Negative filter, passing (disjunction of tests).
497 MatchAndCheck(tests, keys::kExcludeRequestHeadersKey, stage,
498 url_request.get(), &result);
499 EXPECT_TRUE(result);
501 // Third set of test data, corner case -- empty disjunction.
502 GetArrayAsVector(NULL, NULL, 0u, &tests);
503 // Positive filter, failing (no test to pass).
504 MatchAndCheck(tests, keys::kRequestHeadersKey, stage, url_request.get(),
505 &result);
506 EXPECT_FALSE(result);
507 // Negative filter, passing (no test to fail).
508 MatchAndCheck(tests, keys::kExcludeRequestHeadersKey, stage,
509 url_request.get(), &result);
510 EXPECT_TRUE(result);
512 // Fourth set of test data, corner case -- empty conjunction.
513 const size_t kEmptyConjunctionSizes[] = { 0u };
514 GetArrayAsVector(NULL, kEmptyConjunctionSizes, 1u, &tests);
515 // Positive filter, passing (trivial test).
516 MatchAndCheck(tests, keys::kRequestHeadersKey, stage, url_request.get(),
517 &result);
518 EXPECT_TRUE(result);
519 // Negative filter, failing.
520 MatchAndCheck(tests, keys::kExcludeRequestHeadersKey, stage,
521 url_request.get(), &result);
522 EXPECT_FALSE(result);
525 // Here we test WebRequestConditionAttributeResponseHeaders for:
526 // 1. Correct implementation of prefix/suffix/contains/equals matching.
527 // 2. Performing logical disjunction (||) between multiple specifications.
528 // 3. Negating the match in case of 'doesNotContainHeaders'.
529 TEST(WebRequestConditionAttributeTest, ResponseHeaders) {
530 // Necessary for TestURLRequest.
531 base::MessageLoopForIO message_loop;
533 net::test_server::EmbeddedTestServer test_server;
534 test_server.ServeFilesFromDirectory(TestDataPath(
535 "chrome/test/data/extensions/api_test/webrequest/declarative"));
536 ASSERT_TRUE(test_server.InitializeAndWaitUntilReady());
538 net::TestURLRequestContext context;
539 net::TestDelegate delegate;
540 scoped_ptr<net::URLRequest> url_request(
541 context.CreateRequest(test_server.GetURL("/headers.html"),
542 net::DEFAULT_PRIORITY,
543 &delegate,
544 NULL));
545 url_request->Start();
546 base::MessageLoop::current()->Run();
548 // In all the tests below we assume that the server includes the headers
549 // Custom-Header: custom/value
550 // Custom-Header-B: valueA
551 // Custom-Header-B: valueB
552 // Custom-Header-C: valueC, valueD
553 // Custom-Header-D:
554 // in the response, but does not include "Non-existing: void".
556 std::vector< std::vector<const std::string*> > tests;
557 bool result;
559 const RequestStage stage = ON_HEADERS_RECEIVED;
561 // 1.a. -- All these tests should pass.
562 const std::string kPassingCondition[] = {
563 keys::kNamePrefixKey, "Custom",
564 keys::kNameSuffixKey, "m-header", // Header names are case insensitive.
565 keys::kValueContainsKey, "alu",
566 keys::kValueEqualsKey, "custom/value"
568 const size_t kPassingConditionSizes[] = { arraysize(kPassingCondition) };
569 GetArrayAsVector(kPassingCondition, kPassingConditionSizes, 1u, &tests);
570 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(),
571 &result);
572 EXPECT_TRUE(result);
574 // 1.b. -- None of the following tests in the discjunction should pass.
575 const std::string kFailCondition[] = {
576 keys::kNamePrefixKey, " Custom", // Test 1.
577 keys::kNameContainsKey, " -", // Test 2.
578 keys::kValueSuffixKey, "alu", // Test 3.
579 keys::kValueEqualsKey, "custom" // Test 4.
581 const size_t kFailConditionSizes[] = { 2u, 2u, 2u, 2u };
582 GetArrayAsVector(kFailCondition, kFailConditionSizes, 4u, &tests);
583 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(),
584 &result);
585 EXPECT_FALSE(result);
587 // 1.c. -- This should fail (mixing name and value from different headers)
588 const std::string kMixingCondition[] = {
589 keys::kNameSuffixKey, "Header-B",
590 keys::kValueEqualsKey, "custom/value"
592 const size_t kMixingConditionSizes[] = { arraysize(kMixingCondition) };
593 GetArrayAsVector(kMixingCondition, kMixingConditionSizes, 1u, &tests);
594 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(),
595 &result);
596 EXPECT_FALSE(result);
598 // 1.d. -- Test handling multiple values for one header (both should pass).
599 const std::string kMoreValues1[] = {
600 keys::kNameEqualsKey, "Custom-header-b",
601 keys::kValueEqualsKey, "valueA"
603 const size_t kMoreValues1Sizes[] = { arraysize(kMoreValues1) };
604 GetArrayAsVector(kMoreValues1, kMoreValues1Sizes, 1u, &tests);
605 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(),
606 &result);
607 EXPECT_TRUE(result);
608 const std::string kMoreValues2[] = {
609 keys::kNameEqualsKey, "Custom-header-b",
610 keys::kValueEqualsKey, "valueB"
612 const size_t kMoreValues2Sizes[] = { arraysize(kMoreValues2) };
613 GetArrayAsVector(kMoreValues2, kMoreValues2Sizes, 1u, &tests);
614 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(),
615 &result);
616 EXPECT_TRUE(result);
618 // 1.e. -- This should fail as conjunction but pass as disjunction.
619 const std::string kConflict[] = {
620 keys::kNameSuffixKey, "Header", // True for some header.
621 keys::kNameContainsKey, "Header-B" // True for a different header.
623 // First disjunction, no conflict.
624 const size_t kNoConflictSizes[] = { 2u, 2u };
625 GetArrayAsVector(kConflict, kNoConflictSizes, 2u, &tests);
626 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(),
627 &result);
628 EXPECT_TRUE(result);
629 // Then conjunction, conflict.
630 const size_t kConflictSizes[] = { arraysize(kConflict) };
631 GetArrayAsVector(kConflict, kConflictSizes, 1u, &tests);
632 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(),
633 &result);
634 EXPECT_FALSE(result);
636 // 1.f. -- This should pass, checking for correct treatment of ',' in values.
637 const std::string kComma[] = {
638 keys::kNameSuffixKey, "Header-C",
639 keys::kValueEqualsKey, "valueC, valueD"
641 const size_t kCommaSizes[] = { arraysize(kComma) };
642 GetArrayAsVector(kComma, kCommaSizes, 1u, &tests);
643 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(),
644 &result);
645 EXPECT_TRUE(result);
647 // 1.g. -- This should pass, empty values are values as well.
648 const std::string kEmpty[] = {
649 keys::kNameEqualsKey, "custom-header-d",
650 keys::kValueEqualsKey, ""
652 const size_t kEmptySizes[] = { arraysize(kEmpty) };
653 GetArrayAsVector(kEmpty, kEmptySizes, 1u, &tests);
654 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(),
655 &result);
656 EXPECT_TRUE(result);
658 // 1.h. -- Values are case-sensitive, this should fail.
659 const std::string kLowercase[] = {
660 keys::kNameEqualsKey, "Custom-header-b",
661 keys::kValuePrefixKey, "valueb", // valueb != valueB
662 keys::kNameEqualsKey, "Custom-header-b",
663 keys::kValueSuffixKey, "valueb",
664 keys::kNameEqualsKey, "Custom-header-b",
665 keys::kValueContainsKey, "valueb",
666 keys::kNameEqualsKey, "Custom-header-b",
667 keys::kValueEqualsKey, "valueb"
669 const size_t kLowercaseSizes[] = { 4u, 4u, 4u, 4u }; // As disjunction.
670 GetArrayAsVector(kLowercase, kLowercaseSizes, 4u, &tests);
671 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(),
672 &result);
673 EXPECT_FALSE(result);
675 // 1.i. -- Names are case-insensitive, this should pass.
676 const std::string kUppercase[] = {
677 keys::kNamePrefixKey, "CUSTOM-HEADER-B",
678 keys::kNameSuffixKey, "CUSTOM-HEADER-B",
679 keys::kNameEqualsKey, "CUSTOM-HEADER-B",
680 keys::kNameContainsKey, "CUSTOM-HEADER-B"
682 const size_t kUppercaseSizes[] = { arraysize(kUppercase) }; // Conjunction.
683 GetArrayAsVector(kUppercase, kUppercaseSizes, 1u, &tests);
684 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(),
685 &result);
686 EXPECT_TRUE(result);
688 // 2.a. -- This should pass as disjunction, because one of the tests passes.
689 const std::string kDisjunction[] = {
690 keys::kNamePrefixKey, "Non-existing", // This one fails.
691 keys::kNameSuffixKey, "Non-existing", // This one fails.
692 keys::kValueEqualsKey, "void", // This one fails.
693 keys::kValueContainsKey, "alu" // This passes.
695 const size_t kDisjunctionSizes[] = { 2u, 2u, 2u, 2u };
696 GetArrayAsVector(kDisjunction, kDisjunctionSizes, 4u, &tests);
697 MatchAndCheck(tests, keys::kResponseHeadersKey, stage, url_request.get(),
698 &result);
699 EXPECT_TRUE(result);
701 // 3.a. -- This should pass.
702 const std::string kNonExistent[] = {
703 keys::kNameEqualsKey, "Non-existing",
704 keys::kValueEqualsKey, "void"
706 const size_t kNonExistentSizes[] = { arraysize(kNonExistent) };
707 GetArrayAsVector(kNonExistent, kNonExistentSizes, 1u, &tests);
708 MatchAndCheck(tests, keys::kExcludeResponseHeadersKey, stage,
709 url_request.get(), &result);
710 EXPECT_TRUE(result);
712 // 3.b. -- This should fail.
713 const std::string kExisting[] = {
714 keys::kNameEqualsKey, "custom-header-b",
715 keys::kValueEqualsKey, "valueB"
717 const size_t kExistingSize[] = { arraysize(kExisting) };
718 GetArrayAsVector(kExisting, kExistingSize, 1u, &tests);
719 MatchAndCheck(tests, keys::kExcludeResponseHeadersKey, stage,
720 url_request.get(), &result);
721 EXPECT_FALSE(result);
724 } // namespace
725 } // namespace extensions