extension_unittest.cc revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2010 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 "chrome/common/extensions/extension.h" 6 7#if defined(TOOLKIT_GTK) 8#include <gtk/gtk.h> 9#endif 10 11#include "base/format_macros.h" 12#include "base/file_path.h" 13#include "base/file_util.h" 14#include "base/i18n/rtl.h" 15#include "base/path_service.h" 16#include "base/string_number_conversions.h" 17#include "base/string_util.h" 18#include "base/utf_string_conversions.h" 19#include "chrome/common/chrome_paths.h" 20#include "chrome/common/extensions/extension_action.h" 21#include "chrome/common/extensions/extension_constants.h" 22#include "chrome/common/extensions/extension_error_utils.h" 23#include "chrome/common/extensions/extension_resource.h" 24#include "chrome/common/json_value_serializer.h" 25#include "chrome/common/url_constants.h" 26#include "googleurl/src/gurl.h" 27#include "net/base/mime_sniffer.h" 28#include "skia/ext/image_operations.h" 29#include "chrome/test/ui_test_utils.h" 30#include "net/base/mock_host_resolver.h" 31#include "testing/gtest/include/gtest/gtest.h" 32#include "third_party/skia/include/core/SkBitmap.h" 33#include "ui/base/l10n/l10n_util.h" 34#include "ui/gfx/codec/png_codec.h" 35 36namespace keys = extension_manifest_keys; 37namespace values = extension_manifest_values; 38namespace errors = extension_manifest_errors; 39 40namespace { 41 42void CompareLists(const std::vector<std::string>& expected, 43 const std::vector<std::string>& actual) { 44 ASSERT_EQ(expected.size(), actual.size()); 45 46 for (size_t i = 0; i < expected.size(); ++i) { 47 EXPECT_EQ(expected[i], actual[i]); 48 } 49} 50 51static void AddPattern(ExtensionExtent* extent, const std::string& pattern) { 52 int schemes = URLPattern::SCHEME_ALL; 53 extent->AddPattern(URLPattern(schemes, pattern)); 54} 55 56} 57 58class ExtensionTest : public testing::Test { 59}; 60 61// We persist location values in the preferences, so this is a sanity test that 62// someone doesn't accidentally change them. 63TEST(ExtensionTest, LocationValuesTest) { 64 ASSERT_EQ(0, Extension::INVALID); 65 ASSERT_EQ(1, Extension::INTERNAL); 66 ASSERT_EQ(2, Extension::EXTERNAL_PREF); 67 ASSERT_EQ(3, Extension::EXTERNAL_REGISTRY); 68 ASSERT_EQ(4, Extension::LOAD); 69 ASSERT_EQ(5, Extension::COMPONENT); 70} 71 72 73// Please don't put any more manifest tests here!! 74// Move them to extension_manifest_unittest.cc instead and make them use the 75// more data-driven style there instead. 76// Bug: http://crbug.com/38462 77 78 79TEST(ExtensionTest, InitFromValueInvalid) { 80#if defined(OS_WIN) 81 FilePath path(FILE_PATH_LITERAL("c:\\foo")); 82#elif defined(OS_POSIX) 83 FilePath path(FILE_PATH_LITERAL("/foo")); 84#endif 85 scoped_refptr<Extension> extension_ptr(new Extension(path, 86 Extension::INVALID)); 87 Extension& extension = *extension_ptr; 88 int error_code = 0; 89 std::string error; 90 91 // Start with a valid extension manifest 92 FilePath extensions_path; 93 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); 94 extensions_path = extensions_path.AppendASCII("extensions") 95 .AppendASCII("good") 96 .AppendASCII("Extensions") 97 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 98 .AppendASCII("1.0.0.0") 99 .Append(Extension::kManifestFilename); 100 101 JSONFileValueSerializer serializer(extensions_path); 102 scoped_ptr<DictionaryValue> valid_value( 103 static_cast<DictionaryValue*>(serializer.Deserialize(&error_code, 104 &error))); 105 EXPECT_EQ("", error); 106 EXPECT_EQ(0, error_code); 107 ASSERT_TRUE(valid_value.get()); 108 ASSERT_TRUE(extension.InitFromValue(*valid_value, true, false, &error)); 109 ASSERT_EQ("", error); 110 EXPECT_EQ("en_US", extension.default_locale()); 111 112 scoped_ptr<DictionaryValue> input_value; 113 114 // Test missing and invalid versions 115 input_value.reset(valid_value->DeepCopy()); 116 input_value->Remove(keys::kVersion, NULL); 117 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 118 EXPECT_EQ(errors::kInvalidVersion, error); 119 120 input_value->SetInteger(keys::kVersion, 42); 121 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 122 EXPECT_EQ(errors::kInvalidVersion, error); 123 124 // Test missing and invalid names. 125 input_value.reset(valid_value->DeepCopy()); 126 input_value->Remove(keys::kName, NULL); 127 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 128 EXPECT_EQ(errors::kInvalidName, error); 129 130 input_value->SetInteger(keys::kName, 42); 131 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 132 EXPECT_EQ(errors::kInvalidName, error); 133 134 // Test invalid description 135 input_value.reset(valid_value->DeepCopy()); 136 input_value->SetInteger(keys::kDescription, 42); 137 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 138 EXPECT_EQ(errors::kInvalidDescription, error); 139 140 // Test invalid icons 141 input_value.reset(valid_value->DeepCopy()); 142 input_value->SetInteger(keys::kIcons, 42); 143 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 144 EXPECT_EQ(errors::kInvalidIcons, error); 145 146 // Test invalid icon paths 147 input_value.reset(valid_value->DeepCopy()); 148 DictionaryValue* icons = NULL; 149 input_value->GetDictionary(keys::kIcons, &icons); 150 ASSERT_FALSE(NULL == icons); 151 icons->SetInteger(base::IntToString(128), 42); 152 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 153 EXPECT_TRUE(MatchPattern(error, errors::kInvalidIconPath)); 154 155 // Test invalid user scripts list 156 input_value.reset(valid_value->DeepCopy()); 157 input_value->SetInteger(keys::kContentScripts, 42); 158 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 159 EXPECT_EQ(errors::kInvalidContentScriptsList, error); 160 161 // Test invalid user script item 162 input_value.reset(valid_value->DeepCopy()); 163 ListValue* content_scripts = NULL; 164 input_value->GetList(keys::kContentScripts, &content_scripts); 165 ASSERT_FALSE(NULL == content_scripts); 166 content_scripts->Set(0, Value::CreateIntegerValue(42)); 167 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 168 EXPECT_TRUE(MatchPattern(error, errors::kInvalidContentScript)); 169 170 // Test missing and invalid matches array 171 input_value.reset(valid_value->DeepCopy()); 172 input_value->GetList(keys::kContentScripts, &content_scripts); 173 DictionaryValue* user_script = NULL; 174 content_scripts->GetDictionary(0, &user_script); 175 user_script->Remove(keys::kMatches, NULL); 176 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 177 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatches)); 178 179 user_script->Set(keys::kMatches, Value::CreateIntegerValue(42)); 180 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 181 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatches)); 182 183 ListValue* matches = new ListValue; 184 user_script->Set(keys::kMatches, matches); 185 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 186 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatchCount)); 187 188 // Test invalid match element 189 matches->Set(0, Value::CreateIntegerValue(42)); 190 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 191 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatch)); 192 193 matches->Set(0, Value::CreateStringValue("chrome://*/*")); 194 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 195 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatch)); 196 197 // Test missing and invalid files array 198 input_value.reset(valid_value->DeepCopy()); 199 input_value->GetList(keys::kContentScripts, &content_scripts); 200 content_scripts->GetDictionary(0, &user_script); 201 user_script->Remove(keys::kJs, NULL); 202 user_script->Remove(keys::kCss, NULL); 203 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 204 EXPECT_TRUE(MatchPattern(error, errors::kMissingFile)); 205 206 user_script->Set(keys::kJs, Value::CreateIntegerValue(42)); 207 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 208 EXPECT_TRUE(MatchPattern(error, errors::kInvalidJsList)); 209 210 user_script->Set(keys::kCss, new ListValue); 211 user_script->Set(keys::kJs, new ListValue); 212 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 213 EXPECT_TRUE(MatchPattern(error, errors::kMissingFile)); 214 user_script->Remove(keys::kCss, NULL); 215 216 ListValue* files = new ListValue; 217 user_script->Set(keys::kJs, files); 218 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 219 EXPECT_TRUE(MatchPattern(error, errors::kMissingFile)); 220 221 // Test invalid file element 222 files->Set(0, Value::CreateIntegerValue(42)); 223 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 224 EXPECT_TRUE(MatchPattern(error, errors::kInvalidJs)); 225 226 user_script->Remove(keys::kJs, NULL); 227 // Test the css element 228 user_script->Set(keys::kCss, Value::CreateIntegerValue(42)); 229 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 230 EXPECT_TRUE(MatchPattern(error, errors::kInvalidCssList)); 231 232 // Test invalid file element 233 ListValue* css_files = new ListValue; 234 user_script->Set(keys::kCss, css_files); 235 css_files->Set(0, Value::CreateIntegerValue(42)); 236 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 237 EXPECT_TRUE(MatchPattern(error, errors::kInvalidCss)); 238 239 // Test missing and invalid permissions array 240 input_value.reset(valid_value->DeepCopy()); 241 EXPECT_TRUE(extension.InitFromValue(*input_value, true, false, &error)); 242 243 ListValue* permissions = NULL; 244 input_value->GetList(keys::kPermissions, &permissions); 245 ASSERT_FALSE(NULL == permissions); 246 247 permissions = new ListValue; 248 input_value->Set(keys::kPermissions, permissions); 249 EXPECT_TRUE(extension.InitFromValue(*input_value, true, false, &error)); 250 251 input_value->Set(keys::kPermissions, Value::CreateIntegerValue(9)); 252 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 253 EXPECT_TRUE(MatchPattern(error, errors::kInvalidPermissions)); 254 255 input_value.reset(valid_value->DeepCopy()); 256 input_value->GetList(keys::kPermissions, &permissions); 257 permissions->Set(0, Value::CreateIntegerValue(24)); 258 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 259 EXPECT_TRUE(MatchPattern(error, errors::kInvalidPermission)); 260 261 // We allow unknown API permissions, so this will be valid until we better 262 // distinguish between API and host permissions. 263 permissions->Set(0, Value::CreateStringValue("www.google.com")); 264 EXPECT_TRUE(extension.InitFromValue(*input_value, true, false, &error)); 265 266 // Multiple page actions are not allowed. 267 input_value.reset(valid_value->DeepCopy()); 268 DictionaryValue* action = new DictionaryValue; 269 action->SetString(keys::kPageActionId, "MyExtensionActionId"); 270 action->SetString(keys::kName, "MyExtensionActionName"); 271 ListValue* action_list = new ListValue; 272 action_list->Append(action->DeepCopy()); 273 action_list->Append(action); 274 input_value->Set(keys::kPageActions, action_list); 275 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 276 EXPECT_STREQ(errors::kInvalidPageActionsListSize, error.c_str()); 277 278 // Test invalid options page url. 279 input_value.reset(valid_value->DeepCopy()); 280 input_value->Set(keys::kOptionsPage, Value::CreateNullValue()); 281 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 282 EXPECT_TRUE(MatchPattern(error, errors::kInvalidOptionsPage)); 283 284 // Test invalid/empty default locale. 285 input_value.reset(valid_value->DeepCopy()); 286 input_value->Set(keys::kDefaultLocale, Value::CreateIntegerValue(5)); 287 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 288 EXPECT_TRUE(MatchPattern(error, errors::kInvalidDefaultLocale)); 289 290 input_value->Set(keys::kDefaultLocale, Value::CreateStringValue("")); 291 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 292 EXPECT_TRUE(MatchPattern(error, errors::kInvalidDefaultLocale)); 293 294 // Test invalid minimum_chrome_version. 295 input_value.reset(valid_value->DeepCopy()); 296 input_value->Set(keys::kMinimumChromeVersion, Value::CreateIntegerValue(42)); 297 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 298 EXPECT_TRUE(MatchPattern(error, errors::kInvalidMinimumChromeVersion)); 299 300#if !defined(OS_MACOSX) 301 // TODO(aa): The version isn't stamped into the unit test binary on mac. 302 input_value->Set(keys::kMinimumChromeVersion, 303 Value::CreateStringValue("88.8")); 304 EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error)); 305 EXPECT_TRUE(MatchPattern(error, errors::kChromeVersionTooLow)); 306#endif 307} 308 309TEST(ExtensionTest, InitFromValueValid) { 310#if defined(OS_WIN) 311 FilePath path(FILE_PATH_LITERAL("C:\\foo")); 312#elif defined(OS_POSIX) 313 FilePath path(FILE_PATH_LITERAL("/foo")); 314#endif 315 scoped_refptr<Extension> extension_ptr(new Extension(path, 316 Extension::INVALID)); 317 Extension& extension = *extension_ptr; 318 std::string error; 319 DictionaryValue input_value; 320 321 // Test minimal extension 322 input_value.SetString(keys::kVersion, "1.0.0.0"); 323 input_value.SetString(keys::kName, "my extension"); 324 325 EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error)); 326 EXPECT_EQ("", error); 327 EXPECT_TRUE(Extension::IdIsValid(extension.id())); 328 EXPECT_EQ("1.0.0.0", extension.VersionString()); 329 EXPECT_EQ("my extension", extension.name()); 330 EXPECT_EQ(extension.id(), extension.url().host()); 331 EXPECT_EQ(path.value(), extension.path().value()); 332 333 // Test permissions scheme. 334 ListValue* permissions = new ListValue; 335 permissions->Set(0, Value::CreateStringValue("file:///C:/foo.txt")); 336 input_value.Set(keys::kPermissions, permissions); 337 338 // We allow unknown API permissions, so this will be valid until we better 339 // distinguish between API and host permissions. 340 EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error)); 341 input_value.Remove(keys::kPermissions, NULL); 342 343 // Test with an options page. 344 input_value.SetString(keys::kOptionsPage, "options.html"); 345 EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error)); 346 EXPECT_EQ("", error); 347 EXPECT_EQ("chrome-extension", extension.options_url().scheme()); 348 EXPECT_EQ("/options.html", extension.options_url().path()); 349 350 // Test that an empty list of page actions does not stop a browser action 351 // from being loaded. 352 ListValue* empty_list = new ListValue; 353 input_value.Set(keys::kPageActions, empty_list); 354 EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error)); 355 EXPECT_EQ("", error); 356 357#if !defined(OS_MACOSX) 358 // TODO(aa): The version isn't stamped into the unit test binary on mac. 359 // Test with a minimum_chrome_version. 360 input_value.SetString(keys::kMinimumChromeVersion, "1.0"); 361 EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error)); 362 EXPECT_EQ("", error); 363 // The minimum chrome version is not stored in the Extension object. 364#endif 365} 366 367TEST(ExtensionTest, InitFromValueValidNameInRTL) { 368#if defined(TOOLKIT_GTK) 369 GtkTextDirection gtk_dir = gtk_widget_get_default_direction(); 370 gtk_widget_set_default_direction(GTK_TEXT_DIR_RTL); 371#else 372 std::string locale = l10n_util::GetApplicationLocale(""); 373 base::i18n::SetICUDefaultLocale("he"); 374#endif 375 376#if defined(OS_WIN) 377 FilePath path(FILE_PATH_LITERAL("C:\\foo")); 378#elif defined(OS_POSIX) 379 FilePath path(FILE_PATH_LITERAL("/foo")); 380#endif 381 scoped_refptr<Extension> extension_ptr(new Extension(path, 382 Extension::INVALID)); 383 Extension& extension = *extension_ptr; 384 std::string error; 385 DictionaryValue input_value; 386 387 input_value.SetString(keys::kVersion, "1.0.0.0"); 388 // No strong RTL characters in name. 389 std::wstring name(L"Dictionary (by Google)"); 390 input_value.SetString(keys::kName, WideToUTF16Hack(name)); 391 EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error)); 392 EXPECT_EQ("", error); 393 std::wstring localized_name(name); 394 base::i18n::AdjustStringForLocaleDirection(&localized_name); 395 EXPECT_EQ(localized_name, UTF8ToWide(extension.name())); 396 397 // Strong RTL characters in name. 398 name = L"Dictionary (\x05D1\x05D2"L" Google)"; 399 input_value.SetString(keys::kName, WideToUTF16Hack(name)); 400 EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error)); 401 EXPECT_EQ("", error); 402 localized_name = name; 403 base::i18n::AdjustStringForLocaleDirection(&localized_name); 404 EXPECT_EQ(localized_name, UTF8ToWide(extension.name())); 405 406 // Reset locale. 407#if defined(TOOLKIT_GTK) 408 gtk_widget_set_default_direction(gtk_dir); 409#else 410 base::i18n::SetICUDefaultLocale(locale); 411#endif 412} 413 414TEST(ExtensionTest, GetResourceURLAndPath) { 415#if defined(OS_WIN) 416 FilePath path(FILE_PATH_LITERAL("C:\\foo")); 417#elif defined(OS_POSIX) 418 FilePath path(FILE_PATH_LITERAL("/foo")); 419#endif 420 DictionaryValue input_value; 421 input_value.SetString(keys::kVersion, "1.0.0.0"); 422 input_value.SetString(keys::kName, "my extension"); 423 scoped_refptr<Extension> extension(Extension::Create( 424 path, Extension::INVALID, input_value, false, true, NULL)); 425 EXPECT_TRUE(extension.get()); 426 427 EXPECT_EQ(extension->url().spec() + "bar/baz.js", 428 Extension::GetResourceURL(extension->url(), "bar/baz.js").spec()); 429 EXPECT_EQ(extension->url().spec() + "baz.js", 430 Extension::GetResourceURL(extension->url(), 431 "bar/../baz.js").spec()); 432 EXPECT_EQ(extension->url().spec() + "baz.js", 433 Extension::GetResourceURL(extension->url(), "../baz.js").spec()); 434} 435 436TEST(ExtensionTest, LoadPageActionHelper) { 437#if defined(OS_WIN) 438 FilePath path(base::StringPrintf(L"c:\\extension")); 439#else 440 FilePath path(base::StringPrintf("/extension")); 441#endif 442 scoped_refptr<Extension> extension_ptr(new Extension(path, 443 Extension::INVALID)); 444 Extension& extension = *extension_ptr; 445 std::string error_msg; 446 scoped_ptr<ExtensionAction> action; 447 DictionaryValue input; 448 449 // First try with an empty dictionary. 450 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 451 ASSERT_TRUE(action != NULL); 452 ASSERT_TRUE(error_msg.empty()); 453 454 // Now setup some values to use in the action. 455 const std::string id("MyExtensionActionId"); 456 const std::string name("MyExtensionActionName"); 457 std::string img1("image1.png"); 458 std::string img2("image2.png"); 459 460 // Add the dictionary for the contextual action. 461 input.SetString(keys::kPageActionId, id); 462 input.SetString(keys::kName, name); 463 ListValue* icons = new ListValue; 464 icons->Set(0, Value::CreateStringValue(img1)); 465 icons->Set(1, Value::CreateStringValue(img2)); 466 input.Set(keys::kPageActionIcons, icons); 467 468 // Parse and read back the values from the object. 469 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 470 ASSERT_TRUE(NULL != action.get()); 471 ASSERT_TRUE(error_msg.empty()); 472 ASSERT_EQ(id, action->id()); 473 // No title, so fall back to name. 474 ASSERT_EQ(name, action->GetTitle(1)); 475 ASSERT_EQ(2u, action->icon_paths()->size()); 476 ASSERT_EQ(img1, (*action->icon_paths())[0]); 477 ASSERT_EQ(img2, (*action->icon_paths())[1]); 478 479 // Explicitly set the same type and parse again. 480 input.SetString(keys::kType, values::kPageActionTypeTab); 481 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 482 ASSERT_TRUE(NULL != action.get()); 483 ASSERT_TRUE(error_msg.empty()); 484 485 // Make a deep copy of the input and remove one key at a time and see if we 486 // get the right error. 487 scoped_ptr<DictionaryValue> copy; 488 489 // First remove id key. 490 copy.reset(input.DeepCopy()); 491 copy->Remove(keys::kPageActionId, NULL); 492 action.reset(extension.LoadExtensionActionHelper(copy.get(), &error_msg)); 493 ASSERT_TRUE(NULL != action.get()); 494 495 // Then remove the name key. It's optional, so no error. 496 copy.reset(input.DeepCopy()); 497 copy->Remove(keys::kName, NULL); 498 action.reset(extension.LoadExtensionActionHelper(copy.get(), &error_msg)); 499 ASSERT_TRUE(NULL != action.get()); 500 ASSERT_TRUE(action->GetTitle(1).empty()); 501 ASSERT_TRUE(error_msg.empty()); 502 503 // Then remove the icon paths key. 504 copy.reset(input.DeepCopy()); 505 copy->Remove(keys::kPageActionIcons, NULL); 506 action.reset(extension.LoadExtensionActionHelper(copy.get(), &error_msg)); 507 ASSERT_TRUE(NULL != action.get()); 508 error_msg = ""; 509 510 // Now test that we can parse the new format for page actions. 511 512 // Now setup some values to use in the page action. 513 const std::string kTitle("MyExtensionActionTitle"); 514 const std::string kIcon("image1.png"); 515 const std::string kPopupHtmlFile("a_popup.html"); 516 517 // Add the dictionary for the contextual action. 518 input.Clear(); 519 input.SetString(keys::kPageActionDefaultTitle, kTitle); 520 input.SetString(keys::kPageActionDefaultIcon, kIcon); 521 522 // Parse and read back the values from the object. 523 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 524 ASSERT_TRUE(action.get()); 525 ASSERT_TRUE(error_msg.empty()); 526 ASSERT_EQ(kTitle, action->GetTitle(1)); 527 ASSERT_EQ(0u, action->icon_paths()->size()); 528 529 // Invalid title should give an error even with a valid name. 530 input.Clear(); 531 input.SetInteger(keys::kPageActionDefaultTitle, 42); 532 input.SetString(keys::kName, name); 533 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 534 ASSERT_TRUE(NULL == action.get()); 535 ASSERT_STREQ(errors::kInvalidPageActionDefaultTitle, error_msg.c_str()); 536 error_msg = ""; 537 538 // Invalid name should give an error only with no title. 539 input.SetString(keys::kPageActionDefaultTitle, kTitle); 540 input.SetInteger(keys::kName, 123); 541 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 542 ASSERT_TRUE(NULL != action.get()); 543 ASSERT_EQ(kTitle, action->GetTitle(1)); 544 ASSERT_TRUE(error_msg.empty()); 545 546 input.Remove(keys::kPageActionDefaultTitle, NULL); 547 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 548 ASSERT_TRUE(NULL == action.get()); 549 ASSERT_STREQ(errors::kInvalidPageActionName, error_msg.c_str()); 550 error_msg = ""; 551 552 // Test that keys "popup" and "default_popup" both work, but can not 553 // be used at the same time. 554 input.Clear(); 555 input.SetString(keys::kPageActionDefaultTitle, kTitle); 556 input.SetString(keys::kPageActionDefaultIcon, kIcon); 557 558 // LoadExtensionActionHelper expects the extension member |extension_url| 559 // to be set. 560 extension.extension_url_ = 561 GURL(std::string(chrome::kExtensionScheme) + 562 chrome::kStandardSchemeSeparator + 563 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/"); 564 565 // Add key "popup", expect success. 566 input.SetString(keys::kPageActionPopup, kPopupHtmlFile); 567 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 568 ASSERT_TRUE(NULL != action.get()); 569 ASSERT_TRUE(error_msg.empty()); 570 ASSERT_STREQ( 571 extension.url().Resolve(kPopupHtmlFile).spec().c_str(), 572 action->GetPopupUrl(ExtensionAction::kDefaultTabId).spec().c_str()); 573 574 // Add key "default_popup", expect failure. 575 input.SetString(keys::kPageActionDefaultPopup, kPopupHtmlFile); 576 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 577 ASSERT_TRUE(NULL == action.get()); 578 ASSERT_STREQ( 579 ExtensionErrorUtils::FormatErrorMessage( 580 errors::kInvalidPageActionOldAndNewKeys, 581 keys::kPageActionDefaultPopup, 582 keys::kPageActionPopup).c_str(), 583 error_msg.c_str()); 584 error_msg = ""; 585 586 // Remove key "popup", expect success. 587 input.Remove(keys::kPageActionPopup, NULL); 588 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 589 ASSERT_TRUE(NULL != action.get()); 590 ASSERT_TRUE(error_msg.empty()); 591 ASSERT_STREQ( 592 extension.url().Resolve(kPopupHtmlFile).spec().c_str(), 593 action->GetPopupUrl(ExtensionAction::kDefaultTabId).spec().c_str()); 594 595 // Setting default_popup to "" is the same as having no popup. 596 input.Remove(keys::kPageActionDefaultPopup, NULL); 597 input.SetString(keys::kPageActionDefaultPopup, ""); 598 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 599 ASSERT_TRUE(NULL != action.get()); 600 ASSERT_TRUE(error_msg.empty()); 601 EXPECT_FALSE(action->HasPopup(ExtensionAction::kDefaultTabId)); 602 ASSERT_STREQ( 603 "", 604 action->GetPopupUrl(ExtensionAction::kDefaultTabId).spec().c_str()); 605 606 // Setting popup to "" is the same as having no popup. 607 input.Remove(keys::kPageActionDefaultPopup, NULL); 608 input.SetString(keys::kPageActionPopup, ""); 609 action.reset(extension.LoadExtensionActionHelper(&input, &error_msg)); 610 ASSERT_TRUE(NULL != action.get()); 611 ASSERT_TRUE(error_msg.empty()); 612 EXPECT_FALSE(action->HasPopup(ExtensionAction::kDefaultTabId)); 613 ASSERT_STREQ( 614 "", 615 action->GetPopupUrl(ExtensionAction::kDefaultTabId).spec().c_str()); 616} 617 618TEST(ExtensionTest, IdIsValid) { 619 EXPECT_TRUE(Extension::IdIsValid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); 620 EXPECT_TRUE(Extension::IdIsValid("pppppppppppppppppppppppppppppppp")); 621 EXPECT_TRUE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmnop")); 622 EXPECT_TRUE(Extension::IdIsValid("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")); 623 EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmno")); 624 EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmnopa")); 625 EXPECT_FALSE(Extension::IdIsValid("0123456789abcdef0123456789abcdef")); 626 EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmnoq")); 627 EXPECT_FALSE(Extension::IdIsValid("abcdefghijklmnopabcdefghijklmno0")); 628} 629 630TEST(ExtensionTest, GenerateID) { 631 const uint8 public_key_info[] = { 632 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 633 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 634 0x89, 0x02, 0x81, 0x81, 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b, 635 0x0c, 0xdc, 0x51, 0x61, 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08, 636 0x55, 0x84, 0xd5, 0x3a, 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04, 637 0x13, 0x3f, 0x8d, 0xf4, 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a, 638 0xb0, 0x40, 0x53, 0x3a, 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30, 639 0xda, 0x8a, 0x31, 0x4f, 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17, 640 0xde, 0x4e, 0xb9, 0x57, 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89, 641 0x4e, 0xb6, 0x47, 0xff, 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85, 642 0x84, 0x32, 0x33, 0xf3, 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14, 643 0x6f, 0x13, 0x8d, 0xc5, 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18, 644 0x53, 0x56, 0xa6, 0x83, 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6, 645 0x0f, 0x02, 0x03, 0x01, 0x00, 0x01 646 }; 647 648 std::string extension_id; 649 EXPECT_TRUE( 650 Extension::GenerateId( 651 std::string(reinterpret_cast<const char*>(&public_key_info[0]), 652 arraysize(public_key_info)), 653 &extension_id)); 654 EXPECT_EQ("melddjfinppjdikinhbgehiennejpfhp", extension_id); 655} 656 657TEST(ExtensionTest, UpdateUrls) { 658 // Test several valid update urls 659 std::vector<std::string> valid; 660 valid.push_back("http://test.com"); 661 valid.push_back("http://test.com/"); 662 valid.push_back("http://test.com/update"); 663 valid.push_back("http://test.com/update?check=true"); 664 for (size_t i = 0; i < valid.size(); i++) { 665 GURL url(valid[i]); 666 EXPECT_TRUE(url.is_valid()); 667 668 DictionaryValue input_value; 669#if defined(OS_WIN) 670 // (Why %Iu below? This is the single file in the whole code base that 671 // might make use of a WidePRIuS; let's not encourage any more.) 672 FilePath path(base::StringPrintf(L"c:\\extension%Iu", i)); 673#else 674 FilePath path(base::StringPrintf("/extension%" PRIuS, i)); 675#endif 676 std::string error; 677 678 input_value.SetString(keys::kVersion, "1.0"); 679 input_value.SetString(keys::kName, "Test"); 680 input_value.SetString(keys::kUpdateURL, url.spec()); 681 682 scoped_refptr<Extension> extension(Extension::Create( 683 path, Extension::INVALID, input_value, false, true, &error)); 684 EXPECT_TRUE(extension.get()) << error; 685 } 686 687 // Test some invalid update urls 688 std::vector<std::string> invalid; 689 invalid.push_back(""); 690 invalid.push_back("test.com"); 691 valid.push_back("http://test.com/update#whatever"); 692 for (size_t i = 0; i < invalid.size(); i++) { 693 DictionaryValue input_value; 694#if defined(OS_WIN) 695 // (Why %Iu below? This is the single file in the whole code base that 696 // might make use of a WidePRIuS; let's not encourage any more.) 697 FilePath path(base::StringPrintf(L"c:\\extension%Iu", i)); 698#else 699 FilePath path(base::StringPrintf("/extension%" PRIuS, i)); 700#endif 701 std::string error; 702 input_value.SetString(keys::kVersion, "1.0"); 703 input_value.SetString(keys::kName, "Test"); 704 input_value.SetString(keys::kUpdateURL, invalid[i]); 705 706 scoped_refptr<Extension> extension(Extension::Create( 707 path, Extension::INVALID, input_value, false, true, &error)); 708 EXPECT_FALSE(extension.get()); 709 EXPECT_TRUE(MatchPattern(error, errors::kInvalidUpdateURL)); 710 } 711} 712 713// This test ensures that the mimetype sniffing code stays in sync with the 714// actual crx files that we test other parts of the system with. 715TEST(ExtensionTest, MimeTypeSniffing) { 716 FilePath path; 717 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 718 path = path.AppendASCII("extensions").AppendASCII("good.crx"); 719 720 std::string data; 721 ASSERT_TRUE(file_util::ReadFileToString(path, &data)); 722 723 std::string result; 724 EXPECT_TRUE(net::SniffMimeType(data.c_str(), data.size(), 725 GURL("http://www.example.com/foo.crx"), "", &result)); 726 EXPECT_EQ(std::string(Extension::kMimeType), result); 727 728 data.clear(); 729 result.clear(); 730 path = path.DirName().AppendASCII("bad_magic.crx"); 731 ASSERT_TRUE(file_util::ReadFileToString(path, &data)); 732 EXPECT_TRUE(net::SniffMimeType(data.c_str(), data.size(), 733 GURL("http://www.example.com/foo.crx"), "", &result)); 734 EXPECT_EQ("application/octet-stream", result); 735} 736 737static scoped_refptr<Extension> LoadManifest(const std::string& dir, 738 const std::string& test_file) { 739 FilePath path; 740 PathService::Get(chrome::DIR_TEST_DATA, &path); 741 path = path.AppendASCII("extensions") 742 .AppendASCII(dir) 743 .AppendASCII(test_file); 744 745 JSONFileValueSerializer serializer(path); 746 std::string error; 747 scoped_ptr<Value> result(serializer.Deserialize(NULL, &error)); 748 if (!result.get()) { 749 EXPECT_EQ("", error); 750 return NULL; 751 } 752 753 scoped_refptr<Extension> extension = Extension::Create( 754 path.DirName(), Extension::INVALID, 755 *static_cast<DictionaryValue*>(result.get()), false, true, &error); 756 EXPECT_TRUE(extension) << error; 757 return extension; 758} 759 760TEST(ExtensionTest, EffectiveHostPermissions) { 761 scoped_refptr<Extension> extension; 762 ExtensionExtent hosts; 763 764 extension = LoadManifest("effective_host_permissions", "empty.json"); 765 EXPECT_EQ(0u, extension->GetEffectiveHostPermissions().patterns().size()); 766 EXPECT_FALSE(hosts.ContainsURL(GURL("http://www.google.com"))); 767 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts()); 768 769 extension = LoadManifest("effective_host_permissions", "one_host.json"); 770 hosts = extension->GetEffectiveHostPermissions(); 771 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com"))); 772 EXPECT_FALSE(hosts.ContainsURL(GURL("https://www.google.com"))); 773 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts()); 774 775 extension = LoadManifest("effective_host_permissions", 776 "one_host_wildcard.json"); 777 hosts = extension->GetEffectiveHostPermissions(); 778 EXPECT_TRUE(hosts.ContainsURL(GURL("http://google.com"))); 779 EXPECT_TRUE(hosts.ContainsURL(GURL("http://foo.google.com"))); 780 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts()); 781 782 extension = LoadManifest("effective_host_permissions", "two_hosts.json"); 783 hosts = extension->GetEffectiveHostPermissions(); 784 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com"))); 785 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.reddit.com"))); 786 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts()); 787 788 extension = LoadManifest("effective_host_permissions", 789 "https_not_considered.json"); 790 hosts = extension->GetEffectiveHostPermissions(); 791 EXPECT_TRUE(hosts.ContainsURL(GURL("http://google.com"))); 792 EXPECT_TRUE(hosts.ContainsURL(GURL("https://google.com"))); 793 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts()); 794 795 extension = LoadManifest("effective_host_permissions", 796 "two_content_scripts.json"); 797 hosts = extension->GetEffectiveHostPermissions(); 798 EXPECT_TRUE(hosts.ContainsURL(GURL("http://google.com"))); 799 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.reddit.com"))); 800 EXPECT_TRUE(hosts.ContainsURL(GURL("http://news.ycombinator.com"))); 801 EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts()); 802 803 extension = LoadManifest("effective_host_permissions", "all_hosts.json"); 804 hosts = extension->GetEffectiveHostPermissions(); 805 EXPECT_TRUE(hosts.ContainsURL(GURL("http://test/"))); 806 EXPECT_FALSE(hosts.ContainsURL(GURL("https://test/"))); 807 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com"))); 808 EXPECT_TRUE(extension->HasEffectiveAccessToAllHosts()); 809 810 extension = LoadManifest("effective_host_permissions", "all_hosts2.json"); 811 hosts = extension->GetEffectiveHostPermissions(); 812 EXPECT_TRUE(hosts.ContainsURL(GURL("http://test/"))); 813 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com"))); 814 EXPECT_TRUE(extension->HasEffectiveAccessToAllHosts()); 815 816 extension = LoadManifest("effective_host_permissions", "all_hosts3.json"); 817 hosts = extension->GetEffectiveHostPermissions(); 818 EXPECT_FALSE(hosts.ContainsURL(GURL("http://test/"))); 819 EXPECT_TRUE(hosts.ContainsURL(GURL("https://test/"))); 820 EXPECT_TRUE(hosts.ContainsURL(GURL("http://www.google.com"))); 821 EXPECT_TRUE(extension->HasEffectiveAccessToAllHosts()); 822} 823 824TEST(ExtensionTest, IsPrivilegeIncrease) { 825 const struct { 826 const char* base_name; 827 // Increase these sizes if you have more than 10. 828 const char* granted_apis[10]; 829 const char* granted_hosts[10]; 830 bool full_access; 831 bool expect_increase; 832 } kTests[] = { 833 { "allhosts1", {NULL}, {"http://*/", NULL}, false, 834 false }, // all -> all 835 { "allhosts2", {NULL}, {"http://*/", NULL}, false, 836 false }, // all -> one 837 { "allhosts3", {NULL}, {NULL}, false, true }, // one -> all 838 { "hosts1", {NULL}, 839 {"http://www.google.com/", "http://www.reddit.com/", NULL}, false, 840 false }, // http://a,http://b -> http://a,http://b 841 { "hosts2", {NULL}, 842 {"http://www.google.com/", "http://www.reddit.com/", NULL}, false, 843 true }, // http://a,http://b -> https://a,http://*.b 844 { "hosts3", {NULL}, 845 {"http://www.google.com/", "http://www.reddit.com/", NULL}, false, 846 false }, // http://a,http://b -> http://a 847 { "hosts4", {NULL}, 848 {"http://www.google.com/", NULL}, false, 849 true }, // http://a -> http://a,http://b 850 { "hosts5", {"tabs", "notifications", NULL}, 851 {"http://*.example.com/", "http://*.example.com/*", 852 "http://*.example.co.uk/*", "http://*.example.com.au/*", 853 NULL}, false, 854 false }, // http://a,b,c -> http://a,b,c + https://a,b,c 855 { "hosts6", {"tabs", "notifications", NULL}, 856 {"http://*.example.com/", "http://*.example.com/*", NULL}, false, 857 false }, // http://a.com -> http://a.com + http://a.co.uk 858 { "permissions1", {"tabs", NULL}, 859 {NULL}, false, false }, // tabs -> tabs 860 { "permissions2", {"tabs", NULL}, 861 {NULL}, false, true }, // tabs -> tabs,bookmarks 862 { "permissions3", {NULL}, 863 {"http://*/*", NULL}, 864 false, true }, // http://a -> http://a,tabs 865 { "permissions5", {"bookmarks", NULL}, 866 {NULL}, false, true }, // bookmarks -> bookmarks,history 867#if !defined(OS_CHROMEOS) // plugins aren't allowed in ChromeOS 868 { "permissions4", {NULL}, 869 {NULL}, true, false }, // plugin -> plugin,tabs 870 { "plugin1", {NULL}, 871 {NULL}, true, false }, // plugin -> plugin 872 { "plugin2", {NULL}, 873 {NULL}, true, false }, // plugin -> none 874 { "plugin3", {NULL}, 875 {NULL}, false, true }, // none -> plugin 876#endif 877 { "storage", {NULL}, 878 {NULL}, false, false }, // none -> storage 879 { "notifications", {NULL}, 880 {NULL}, false, false } // none -> notifications 881 }; 882 883 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) { 884 scoped_refptr<Extension> old_extension( 885 LoadManifest("allow_silent_upgrade", 886 std::string(kTests[i].base_name) + "_old.json")); 887 scoped_refptr<Extension> new_extension( 888 LoadManifest("allow_silent_upgrade", 889 std::string(kTests[i].base_name) + "_new.json")); 890 891 std::set<std::string> granted_apis; 892 for (size_t j = 0; kTests[i].granted_apis[j] != NULL; ++j) 893 granted_apis.insert(kTests[i].granted_apis[j]); 894 895 ExtensionExtent granted_hosts; 896 for (size_t j = 0; kTests[i].granted_hosts[j] != NULL; ++j) 897 AddPattern(&granted_hosts, kTests[i].granted_hosts[j]); 898 899 EXPECT_TRUE(new_extension.get()) << kTests[i].base_name << "_new.json"; 900 if (!new_extension.get()) 901 continue; 902 903 EXPECT_EQ(kTests[i].expect_increase, 904 Extension::IsPrivilegeIncrease(kTests[i].full_access, 905 granted_apis, 906 granted_hosts, 907 new_extension.get())) 908 << kTests[i].base_name; 909 } 910} 911 912TEST(ExtensionTest, PermissionMessages) { 913 // Ensure that all permissions that needs to show install UI actually have 914 // strings associated with them. 915 916 std::set<std::string> skip; 917 918 // These are considered "nuisance" or "trivial" permissions that don't need 919 // a prompt. 920 skip.insert(Extension::kContextMenusPermission); 921 skip.insert(Extension::kIdlePermission); 922 skip.insert(Extension::kNotificationPermission); 923 skip.insert(Extension::kUnlimitedStoragePermission); 924 skip.insert(Extension::kContentSettingsPermission); 925 926 // TODO(erikkay) add a string for this permission. 927 skip.insert(Extension::kBackgroundPermission); 928 929 // The cookie permission does nothing unless you have associated host 930 // permissions. 931 skip.insert(Extension::kCookiePermission); 932 933 // The proxy permission is warned as part of host permission checks. 934 skip.insert(Extension::kProxyPermission); 935 936 // If you've turned on the experimental command-line flag, we don't need 937 // to warn you further. 938 skip.insert(Extension::kExperimentalPermission); 939 940 // This is only usable by component extensions. 941 skip.insert(Extension::kWebstorePrivatePermission); 942 943 for (size_t i = 0; i < Extension::kNumPermissions; ++i) { 944 int message_id = Extension::kPermissions[i].message_id; 945 std::string name = Extension::kPermissions[i].name; 946 if (skip.count(name)) 947 EXPECT_EQ(0, message_id) << "unexpected message_id for " << name; 948 else 949 EXPECT_NE(0, message_id) << "missing message_id for " << name; 950 } 951} 952 953// Returns a copy of |source| resized to |size| x |size|. 954static SkBitmap ResizedCopy(const SkBitmap& source, int size) { 955 return skia::ImageOperations::Resize(source, 956 skia::ImageOperations::RESIZE_LANCZOS3, 957 size, 958 size); 959} 960 961static bool SizeEquals(const SkBitmap& bitmap, const gfx::Size& size) { 962 return bitmap.width() == size.width() && bitmap.height() == size.height(); 963} 964 965TEST(ExtensionTest, ImageCaching) { 966 FilePath path; 967 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 968 path = path.AppendASCII("extensions"); 969 970 // Initialize the Extension. 971 std::string errors; 972 DictionaryValue values; 973 values.SetString(keys::kName, "test"); 974 values.SetString(keys::kVersion, "0.1"); 975 scoped_refptr<Extension> extension(Extension::Create( 976 path, Extension::INVALID, values, false, true, &errors)); 977 ASSERT_TRUE(extension.get()); 978 979 // Create an ExtensionResource pointing at an icon. 980 FilePath icon_relative_path(FILE_PATH_LITERAL("icon3.png")); 981 ExtensionResource resource(extension->id(), 982 extension->path(), 983 icon_relative_path); 984 985 // Read in the icon file. 986 FilePath icon_absolute_path = extension->path().Append(icon_relative_path); 987 std::string raw_png; 988 ASSERT_TRUE(file_util::ReadFileToString(icon_absolute_path, &raw_png)); 989 SkBitmap image; 990 ASSERT_TRUE(gfx::PNGCodec::Decode( 991 reinterpret_cast<const unsigned char*>(raw_png.data()), 992 raw_png.length(), 993 &image)); 994 995 // Make sure the icon file is the size we expect. 996 gfx::Size original_size(66, 66); 997 ASSERT_EQ(image.width(), original_size.width()); 998 ASSERT_EQ(image.height(), original_size.height()); 999 1000 // Create two resized versions at size 16x16 and 24x24. 1001 SkBitmap image16 = ResizedCopy(image, 16); 1002 SkBitmap image24 = ResizedCopy(image, 24); 1003 1004 gfx::Size size16(16, 16); 1005 gfx::Size size24(24, 24); 1006 1007 // Cache the 16x16 copy. 1008 EXPECT_FALSE(extension->HasCachedImage(resource, size16)); 1009 extension->SetCachedImage(resource, image16, original_size); 1010 EXPECT_TRUE(extension->HasCachedImage(resource, size16)); 1011 EXPECT_TRUE(SizeEquals(extension->GetCachedImage(resource, size16), size16)); 1012 EXPECT_FALSE(extension->HasCachedImage(resource, size24)); 1013 EXPECT_FALSE(extension->HasCachedImage(resource, original_size)); 1014 1015 // Cache the 24x24 copy. 1016 extension->SetCachedImage(resource, image24, original_size); 1017 EXPECT_TRUE(extension->HasCachedImage(resource, size24)); 1018 EXPECT_TRUE(SizeEquals(extension->GetCachedImage(resource, size24), size24)); 1019 EXPECT_FALSE(extension->HasCachedImage(resource, original_size)); 1020 1021 // Cache the original, and verify that it gets returned when we ask for a 1022 // max_size that is larger than the original. 1023 gfx::Size size128(128, 128); 1024 EXPECT_TRUE(image.width() < size128.width() && 1025 image.height() < size128.height()); 1026 extension->SetCachedImage(resource, image, original_size); 1027 EXPECT_TRUE(extension->HasCachedImage(resource, original_size)); 1028 EXPECT_TRUE(extension->HasCachedImage(resource, size128)); 1029 EXPECT_TRUE(SizeEquals(extension->GetCachedImage(resource, original_size), 1030 original_size)); 1031 EXPECT_TRUE(SizeEquals(extension->GetCachedImage(resource, size128), 1032 original_size)); 1033 EXPECT_EQ(extension->GetCachedImage(resource, original_size).getPixels(), 1034 extension->GetCachedImage(resource, size128).getPixels()); 1035} 1036 1037// Tests that the old permission name "unlimited_storage" still works for 1038// backwards compatibility (we renamed it to "unlimitedStorage"). 1039TEST(ExtensionTest, OldUnlimitedStoragePermission) { 1040 ScopedTempDir directory; 1041 ASSERT_TRUE(directory.CreateUniqueTempDir()); 1042 FilePath extension_path = directory.path(); 1043 DictionaryValue dictionary; 1044 1045 // The two required keys. 1046 dictionary.SetString(extension_manifest_keys::kName, "test"); 1047 dictionary.SetString(extension_manifest_keys::kVersion, "0.1"); 1048 1049 // Create a permissions list containing "unlimited_storage" and add it. 1050 ListValue* permissions = new ListValue(); 1051 const char* old_unlimited = "unlimited_storage"; 1052 EXPECT_STREQ(old_unlimited, Extension::kOldUnlimitedStoragePermission); 1053 permissions->Append(Value::CreateStringValue(old_unlimited)); 1054 dictionary.Set(extension_manifest_keys::kPermissions, permissions); 1055 1056 // Initialize the extension and make sure the permission for unlimited storage 1057 // is present. 1058 std::string errors; 1059 scoped_refptr<Extension> extension(Extension::Create( 1060 extension_path, Extension::INVALID, dictionary, false, true, &errors)); 1061 EXPECT_TRUE(extension.get()); 1062 EXPECT_TRUE(extension->HasApiPermission( 1063 Extension::kUnlimitedStoragePermission)); 1064} 1065 1066// This tests the API permissions with an empty manifest (one that just 1067// specifies a name and a version and nothing else). 1068TEST(ExtensionTest, ApiPermissions) { 1069 const struct { 1070 const char* permission_name; 1071 bool expect_success; 1072 } kTests[] = { 1073 // Negative test. 1074 { "non_existing_permission", false }, 1075 // Test default module/package permission. 1076 { "browserAction", true }, 1077 { "browserActions", true }, 1078 { "devtools", true }, 1079 { "extension", true }, 1080 { "i18n", true }, 1081 { "pageAction", true }, 1082 { "pageActions", true }, 1083 { "test", true }, 1084 // Some negative tests. 1085 { "bookmarks", false }, 1086 { "cookies", false }, 1087 { "history", false }, 1088 { "tabs.onUpdated", false }, 1089 // Make sure we find the module name after stripping '.' and '/'. 1090 { "browserAction/abcd/onClick", true }, 1091 { "browserAction.abcd.onClick", true }, 1092 // Test Tabs functions. 1093 { "tabs.create", true}, 1094 { "tabs.update", true}, 1095 { "tabs.getSelected", false}, 1096 }; 1097 1098 scoped_refptr<Extension> extension; 1099 extension = LoadManifest("empty_manifest", "empty.json"); 1100 1101 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) { 1102 EXPECT_EQ(kTests[i].expect_success, 1103 extension->HasApiPermission(kTests[i].permission_name)) 1104 << "Permission being tested: " << kTests[i].permission_name; 1105 } 1106} 1107 1108TEST(ExtensionTest, GetDistinctHostsForDisplay) { 1109 std::vector<std::string> expected; 1110 expected.push_back("www.foo.com"); 1111 expected.push_back("www.bar.com"); 1112 expected.push_back("www.baz.com"); 1113 URLPatternList actual; 1114 1115 { 1116 SCOPED_TRACE("no dupes"); 1117 1118 // Simple list with no dupes. 1119 actual.push_back( 1120 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path")); 1121 actual.push_back( 1122 URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/path")); 1123 actual.push_back( 1124 URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path")); 1125 CompareLists(expected, 1126 Extension::GetDistinctHostsForDisplay(actual)); 1127 } 1128 1129 { 1130 SCOPED_TRACE("two dupes"); 1131 1132 // Add some dupes. 1133 actual.push_back( 1134 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path")); 1135 actual.push_back( 1136 URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path")); 1137 CompareLists(expected, 1138 Extension::GetDistinctHostsForDisplay(actual)); 1139 } 1140 1141 { 1142 SCOPED_TRACE("schemes differ"); 1143 1144 // Add a pattern that differs only by scheme. This should be filtered out. 1145 actual.push_back( 1146 URLPattern(URLPattern::SCHEME_HTTPS, "https://www.bar.com/path")); 1147 CompareLists(expected, 1148 Extension::GetDistinctHostsForDisplay(actual)); 1149 } 1150 1151 { 1152 SCOPED_TRACE("paths differ"); 1153 1154 // Add some dupes by path. 1155 actual.push_back( 1156 URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/pathypath")); 1157 CompareLists(expected, 1158 Extension::GetDistinctHostsForDisplay(actual)); 1159 } 1160 1161 { 1162 SCOPED_TRACE("subdomains differ"); 1163 1164 // We don't do anything special for subdomains. 1165 actual.push_back( 1166 URLPattern(URLPattern::SCHEME_HTTP, "http://monkey.www.bar.com/path")); 1167 actual.push_back( 1168 URLPattern(URLPattern::SCHEME_HTTP, "http://bar.com/path")); 1169 1170 expected.push_back("monkey.www.bar.com"); 1171 expected.push_back("bar.com"); 1172 1173 CompareLists(expected, 1174 Extension::GetDistinctHostsForDisplay(actual)); 1175 } 1176 1177 { 1178 SCOPED_TRACE("RCDs differ"); 1179 1180 // Now test for RCD uniquing. 1181 actual.push_back( 1182 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path")); 1183 actual.push_back( 1184 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path")); 1185 actual.push_back( 1186 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.de/path")); 1187 actual.push_back( 1188 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca.us/path")); 1189 actual.push_back( 1190 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path")); 1191 actual.push_back( 1192 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com.my/path")); 1193 1194 // This is an unknown RCD, which shouldn't be uniqued out. 1195 actual.push_back( 1196 URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path")); 1197 1198 expected.push_back("www.foo.xyzzy"); 1199 1200 CompareLists(expected, 1201 Extension::GetDistinctHostsForDisplay(actual)); 1202 } 1203 1204 { 1205 SCOPED_TRACE("wildcards"); 1206 1207 actual.push_back( 1208 URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com/*")); 1209 1210 expected.push_back("*.google.com"); 1211 1212 CompareLists(expected, 1213 Extension::GetDistinctHostsForDisplay(actual)); 1214 } 1215} 1216 1217TEST(ExtensionTest, IsElevatedHostList) { 1218 URLPatternList list1; 1219 URLPatternList list2; 1220 1221 list1.push_back( 1222 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path")); 1223 list1.push_back( 1224 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path")); 1225 1226 // Test that the host order does not matter. 1227 list2.push_back( 1228 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path")); 1229 list2.push_back( 1230 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path")); 1231 1232 EXPECT_FALSE(Extension::IsElevatedHostList(list1, list2)); 1233 EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1)); 1234 1235 // Test that paths are ignored. 1236 list2.clear(); 1237 list2.push_back( 1238 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/*")); 1239 EXPECT_FALSE(Extension::IsElevatedHostList(list1, list2)); 1240 EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1)); 1241 1242 // Test that RCDs are ignored. 1243 list2.clear(); 1244 list2.push_back( 1245 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/*")); 1246 EXPECT_FALSE(Extension::IsElevatedHostList(list1, list2)); 1247 EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1)); 1248 1249 // Test that subdomain wildcards are handled properly. 1250 list2.clear(); 1251 list2.push_back( 1252 URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com.hk/*")); 1253 EXPECT_TRUE(Extension::IsElevatedHostList(list1, list2)); 1254 //TODO(jstritar): Does not match subdomains properly. http://crbug.com/65337 1255 //EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1)); 1256 1257 // Test that different domains count as different hosts. 1258 list2.clear(); 1259 list2.push_back( 1260 URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path")); 1261 list2.push_back( 1262 URLPattern(URLPattern::SCHEME_HTTP, "http://www.example.org/path")); 1263 EXPECT_TRUE(Extension::IsElevatedHostList(list1, list2)); 1264 EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1)); 1265 1266 // Test that different subdomains count as different hosts. 1267 list2.clear(); 1268 list2.push_back( 1269 URLPattern(URLPattern::SCHEME_HTTP, "http://mail.google.com/*")); 1270 EXPECT_TRUE(Extension::IsElevatedHostList(list1, list2)); 1271 EXPECT_TRUE(Extension::IsElevatedHostList(list2, list1)); 1272} 1273 1274TEST(ExtensionTest, GenerateId) { 1275 std::string result; 1276 EXPECT_FALSE(Extension::GenerateId("", &result)); 1277 1278 EXPECT_TRUE(Extension::GenerateId("test", &result)); 1279 EXPECT_EQ(result, "jpignaibiiemhngfjkcpokkamffknabf"); 1280 1281 EXPECT_TRUE(Extension::GenerateId("_", &result)); 1282 EXPECT_EQ(result, "ncocknphbhhlhkikpnnlmbcnbgdempcd"); 1283 1284 EXPECT_TRUE(Extension::GenerateId( 1285 "this_string_is_longer_than_a_single_sha256_hash_digest", &result)); 1286 EXPECT_EQ(result, "jimneklojkjdibfkgiiophfhjhbdgcfi"); 1287} 1288