1 // Copyright (c) 2011 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 "base/command_line.h"
6 #include "base/file_path.h"
7 #include "base/file_util.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/path_service.h"
10 #include "base/string_number_conversions.h"
11 #include "base/string_util.h"
12 #include "base/utf_string_conversions.h"
13 #include "chrome/common/chrome_paths.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/extensions/extension.h"
16 #include "chrome/common/extensions/extension_constants.h"
17 #include "chrome/common/extensions/extension_error_utils.h"
18 #include "chrome/common/extensions/extension_sidebar_defaults.h"
19 #include "chrome/common/extensions/file_browser_handler.h"
20 #include "chrome/common/extensions/url_pattern.h"
21 #include "content/common/json_value_serializer.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 namespace errors = extension_manifest_errors;
25 namespace keys = extension_manifest_keys;
26
27 class ExtensionManifestTest : public testing::Test {
28 public:
ExtensionManifestTest()29 ExtensionManifestTest() : enable_apps_(true) {}
30
31 protected:
LoadManifestFile(const std::string & filename,std::string * error)32 DictionaryValue* LoadManifestFile(const std::string& filename,
33 std::string* error) {
34 FilePath path;
35 PathService::Get(chrome::DIR_TEST_DATA, &path);
36 path = path.AppendASCII("extensions")
37 .AppendASCII("manifest_tests")
38 .AppendASCII(filename.c_str());
39 EXPECT_TRUE(file_util::PathExists(path));
40
41 JSONFileValueSerializer serializer(path);
42 return static_cast<DictionaryValue*>(serializer.Deserialize(NULL, error));
43 }
44
LoadExtensionWithLocation(DictionaryValue * value,Extension::Location location,bool strict_error_checks,std::string * error)45 scoped_refptr<Extension> LoadExtensionWithLocation(
46 DictionaryValue* value,
47 Extension::Location location,
48 bool strict_error_checks,
49 std::string* error) {
50 FilePath path;
51 PathService::Get(chrome::DIR_TEST_DATA, &path);
52 path = path.AppendASCII("extensions").AppendASCII("manifest_tests");
53 int flags = Extension::NO_FLAGS;
54 if (strict_error_checks)
55 flags |= Extension::STRICT_ERROR_CHECKS;
56 return Extension::Create(path.DirName(), location, *value, flags, error);
57 }
58
LoadExtension(const std::string & name,std::string * error)59 scoped_refptr<Extension> LoadExtension(const std::string& name,
60 std::string* error) {
61 return LoadExtensionWithLocation(name, Extension::INTERNAL, false, error);
62 }
63
LoadExtensionStrict(const std::string & name,std::string * error)64 scoped_refptr<Extension> LoadExtensionStrict(const std::string& name,
65 std::string* error) {
66 return LoadExtensionWithLocation(name, Extension::INTERNAL, true, error);
67 }
68
LoadExtension(DictionaryValue * value,std::string * error)69 scoped_refptr<Extension> LoadExtension(DictionaryValue* value,
70 std::string* error) {
71 // Loading as an installed extension disables strict error checks.
72 return LoadExtensionWithLocation(value, Extension::INTERNAL, false, error);
73 }
74
LoadExtensionWithLocation(const std::string & name,Extension::Location location,bool strict_error_checks,std::string * error)75 scoped_refptr<Extension> LoadExtensionWithLocation(
76 const std::string& name,
77 Extension::Location location,
78 bool strict_error_checks,
79 std::string* error) {
80 scoped_ptr<DictionaryValue> value(LoadManifestFile(name, error));
81 if (!value.get())
82 return NULL;
83 return LoadExtensionWithLocation(value.get(), location,
84 strict_error_checks, error);
85 }
86
LoadAndExpectSuccess(const std::string & name)87 scoped_refptr<Extension> LoadAndExpectSuccess(const std::string& name) {
88 std::string error;
89 scoped_refptr<Extension> extension = LoadExtension(name, &error);
90 EXPECT_TRUE(extension) << name;
91 EXPECT_EQ("", error) << name;
92 return extension;
93 }
94
LoadStrictAndExpectSuccess(const std::string & name)95 scoped_refptr<Extension> LoadStrictAndExpectSuccess(const std::string& name) {
96 std::string error;
97 scoped_refptr<Extension> extension = LoadExtensionStrict(name, &error);
98 EXPECT_TRUE(extension) << name;
99 EXPECT_EQ("", error) << name;
100 return extension;
101 }
102
LoadAndExpectSuccess(DictionaryValue * manifest,const std::string & name)103 scoped_refptr<Extension> LoadAndExpectSuccess(DictionaryValue* manifest,
104 const std::string& name) {
105 std::string error;
106 scoped_refptr<Extension> extension = LoadExtension(manifest, &error);
107 EXPECT_TRUE(extension) << "Unexpected success for " << name;
108 EXPECT_EQ("", error) << "Unexpected no error for " << name;
109 return extension;
110 }
111
VerifyExpectedError(Extension * extension,const std::string & name,const std::string & error,const std::string & expected_error)112 void VerifyExpectedError(Extension* extension,
113 const std::string& name,
114 const std::string& error,
115 const std::string& expected_error) {
116 EXPECT_FALSE(extension) <<
117 "Expected failure loading extension '" << name <<
118 "', but didn't get one.";
119 EXPECT_TRUE(MatchPattern(error, expected_error)) << name <<
120 " expected '" << expected_error << "' but got '" << error << "'";
121 }
122
LoadAndExpectError(const std::string & name,const std::string & expected_error)123 void LoadAndExpectError(const std::string& name,
124 const std::string& expected_error) {
125 std::string error;
126 scoped_refptr<Extension> extension(LoadExtension(name, &error));
127 VerifyExpectedError(extension.get(), name, error, expected_error);
128 }
129
LoadAndExpectErrorStrict(const std::string & name,const std::string & expected_error)130 void LoadAndExpectErrorStrict(const std::string& name,
131 const std::string& expected_error) {
132 std::string error;
133 scoped_refptr<Extension> extension(LoadExtensionStrict(name, &error));
134 VerifyExpectedError(extension.get(), name, error, expected_error);
135 }
136
LoadAndExpectError(DictionaryValue * manifest,const std::string & name,const std::string & expected_error)137 void LoadAndExpectError(DictionaryValue* manifest,
138 const std::string& name,
139 const std::string& expected_error) {
140 std::string error;
141 scoped_refptr<Extension> extension(LoadExtension(manifest, &error));
142 VerifyExpectedError(extension.get(), name, error, expected_error);
143 }
144
145 bool enable_apps_;
146 };
147
TEST_F(ExtensionManifestTest,ValidApp)148 TEST_F(ExtensionManifestTest, ValidApp) {
149 scoped_refptr<Extension> extension(LoadAndExpectSuccess("valid_app.json"));
150 ASSERT_EQ(2u, extension->web_extent().patterns().size());
151 EXPECT_EQ("http://www.google.com/mail/*",
152 extension->web_extent().patterns()[0].GetAsString());
153 EXPECT_EQ("http://www.google.com/foobar/*",
154 extension->web_extent().patterns()[1].GetAsString());
155 EXPECT_EQ(extension_misc::LAUNCH_TAB, extension->launch_container());
156 EXPECT_EQ("http://www.google.com/mail/", extension->launch_web_url());
157 }
158
TEST_F(ExtensionManifestTest,AppWebUrls)159 TEST_F(ExtensionManifestTest, AppWebUrls) {
160 LoadAndExpectError("web_urls_wrong_type.json",
161 errors::kInvalidWebURLs);
162 LoadAndExpectError(
163 "web_urls_invalid_1.json",
164 ExtensionErrorUtils::FormatErrorMessage(
165 errors::kInvalidWebURL,
166 base::IntToString(0),
167 errors::kExpectString));
168
169 LoadAndExpectError(
170 "web_urls_invalid_2.json",
171 ExtensionErrorUtils::FormatErrorMessage(
172 errors::kInvalidWebURL,
173 base::IntToString(0),
174 URLPattern::GetParseResultString(
175 URLPattern::PARSE_ERROR_MISSING_SCHEME_SEPARATOR)));
176
177 LoadAndExpectError(
178 "web_urls_invalid_3.json",
179 ExtensionErrorUtils::FormatErrorMessage(
180 errors::kInvalidWebURL,
181 base::IntToString(0),
182 errors::kNoWildCardsInPaths));
183
184 LoadAndExpectError(
185 "web_urls_invalid_4.json",
186 ExtensionErrorUtils::FormatErrorMessage(
187 errors::kInvalidWebURL,
188 base::IntToString(0),
189 errors::kCannotClaimAllURLsInExtent));
190
191 LoadAndExpectError(
192 "web_urls_invalid_5.json",
193 ExtensionErrorUtils::FormatErrorMessage(
194 errors::kInvalidWebURL,
195 base::IntToString(1),
196 errors::kCannotClaimAllHostsInExtent));
197
198 // Ports in app.urls only raise an error when loading as a
199 // developer would.
200 LoadAndExpectSuccess("web_urls_invalid_has_port.json");
201 LoadAndExpectErrorStrict(
202 "web_urls_invalid_has_port.json",
203 ExtensionErrorUtils::FormatErrorMessage(
204 errors::kInvalidWebURL,
205 base::IntToString(1),
206 URLPattern::GetParseResultString(URLPattern::PARSE_ERROR_HAS_COLON)));
207
208
209 scoped_refptr<Extension> extension(
210 LoadAndExpectSuccess("web_urls_default.json"));
211 ASSERT_EQ(1u, extension->web_extent().patterns().size());
212 EXPECT_EQ("*://www.google.com/*",
213 extension->web_extent().patterns()[0].GetAsString());
214 }
215
TEST_F(ExtensionManifestTest,AppLaunchContainer)216 TEST_F(ExtensionManifestTest, AppLaunchContainer) {
217 scoped_refptr<Extension> extension;
218
219 extension = LoadAndExpectSuccess("launch_tab.json");
220 EXPECT_EQ(extension_misc::LAUNCH_TAB, extension->launch_container());
221
222 extension = LoadAndExpectSuccess("launch_panel.json");
223 EXPECT_EQ(extension_misc::LAUNCH_PANEL, extension->launch_container());
224
225 extension = LoadAndExpectSuccess("launch_default.json");
226 EXPECT_EQ(extension_misc::LAUNCH_TAB, extension->launch_container());
227
228 extension = LoadAndExpectSuccess("launch_width.json");
229 EXPECT_EQ(640, extension->launch_width());
230
231 extension = LoadAndExpectSuccess("launch_height.json");
232 EXPECT_EQ(480, extension->launch_height());
233
234 LoadAndExpectError("launch_window.json",
235 errors::kInvalidLaunchContainer);
236 LoadAndExpectError("launch_container_invalid_type.json",
237 errors::kInvalidLaunchContainer);
238 LoadAndExpectError("launch_container_invalid_value.json",
239 errors::kInvalidLaunchContainer);
240 LoadAndExpectError("launch_container_without_launch_url.json",
241 errors::kLaunchURLRequired);
242 LoadAndExpectError("launch_width_invalid.json",
243 errors::kInvalidLaunchWidthContainer);
244 LoadAndExpectError("launch_width_negative.json",
245 errors::kInvalidLaunchWidth);
246 LoadAndExpectError("launch_height_invalid.json",
247 errors::kInvalidLaunchHeightContainer);
248 LoadAndExpectError("launch_height_negative.json",
249 errors::kInvalidLaunchHeight);
250 }
251
TEST_F(ExtensionManifestTest,AppLaunchURL)252 TEST_F(ExtensionManifestTest, AppLaunchURL) {
253 LoadAndExpectError("launch_path_and_url.json",
254 errors::kLaunchPathAndURLAreExclusive);
255 LoadAndExpectError("launch_path_invalid_type.json",
256 errors::kInvalidLaunchLocalPath);
257 LoadAndExpectError("launch_path_invalid_value.json",
258 errors::kInvalidLaunchLocalPath);
259 LoadAndExpectError("launch_url_invalid_type_1.json",
260 errors::kInvalidLaunchWebURL);
261 LoadAndExpectError("launch_url_invalid_type_2.json",
262 errors::kInvalidLaunchWebURL);
263 LoadAndExpectError("launch_url_invalid_type_3.json",
264 errors::kInvalidLaunchWebURL);
265
266 scoped_refptr<Extension> extension;
267 extension = LoadAndExpectSuccess("launch_local_path.json");
268 EXPECT_EQ(extension->url().spec() + "launch.html",
269 extension->GetFullLaunchURL().spec());
270
271 LoadAndExpectError("launch_web_url_relative.json",
272 errors::kInvalidLaunchWebURL);
273
274 extension = LoadAndExpectSuccess("launch_web_url_absolute.json");
275 EXPECT_EQ(GURL("http://www.google.com/launch.html"),
276 extension->GetFullLaunchURL());
277 }
278
TEST_F(ExtensionManifestTest,Override)279 TEST_F(ExtensionManifestTest, Override) {
280 LoadAndExpectError("override_newtab_and_history.json",
281 errors::kMultipleOverrides);
282 LoadAndExpectError("override_invalid_page.json",
283 errors::kInvalidChromeURLOverrides);
284
285 scoped_refptr<Extension> extension;
286
287 extension = LoadAndExpectSuccess("override_new_tab.json");
288 EXPECT_EQ(extension->url().spec() + "newtab.html",
289 extension->GetChromeURLOverrides().find("newtab")->second.spec());
290
291 extension = LoadAndExpectSuccess("override_history.json");
292 EXPECT_EQ(extension->url().spec() + "history.html",
293 extension->GetChromeURLOverrides().find("history")->second.spec());
294 }
295
TEST_F(ExtensionManifestTest,ChromeURLPermissionInvalid)296 TEST_F(ExtensionManifestTest, ChromeURLPermissionInvalid) {
297 LoadAndExpectError("permission_chrome_url_invalid.json",
298 errors::kInvalidPermissionScheme);
299 }
300
TEST_F(ExtensionManifestTest,ChromeResourcesPermissionValidOnlyForComponents)301 TEST_F(ExtensionManifestTest, ChromeResourcesPermissionValidOnlyForComponents) {
302 LoadAndExpectError("permission_chrome_resources_url.json",
303 errors::kInvalidPermissionScheme);
304 std::string error;
305 scoped_refptr<Extension> extension;
306 extension = LoadExtensionWithLocation(
307 "permission_chrome_resources_url.json",
308 Extension::COMPONENT,
309 true, // Strict error checking
310 &error);
311 EXPECT_EQ("", error);
312 }
313
TEST_F(ExtensionManifestTest,InvalidContentScriptMatchPattern)314 TEST_F(ExtensionManifestTest, InvalidContentScriptMatchPattern) {
315
316 // chrome:// urls are not allowed.
317 LoadAndExpectError(
318 "content_script_chrome_url_invalid.json",
319 ExtensionErrorUtils::FormatErrorMessage(
320 errors::kInvalidMatch,
321 base::IntToString(0),
322 base::IntToString(0),
323 URLPattern::GetParseResultString(
324 URLPattern::PARSE_ERROR_INVALID_SCHEME)));
325
326 // Match paterns must be strings.
327 LoadAndExpectError(
328 "content_script_match_pattern_not_string.json",
329 ExtensionErrorUtils::FormatErrorMessage(
330 errors::kInvalidMatch,
331 base::IntToString(0),
332 base::IntToString(0),
333 errors::kExpectString));
334
335 // Ports in match patterns cause an error, but only when loading
336 // in developer mode.
337 LoadAndExpectSuccess("forbid_ports_in_content_scripts.json");
338
339 // Loading as a developer would should give an error.
340 LoadAndExpectErrorStrict(
341 "forbid_ports_in_content_scripts.json",
342 ExtensionErrorUtils::FormatErrorMessage(
343 errors::kInvalidMatch,
344 base::IntToString(1),
345 base::IntToString(0),
346 URLPattern::GetParseResultString(
347 URLPattern::PARSE_ERROR_HAS_COLON)));
348 }
349
TEST_F(ExtensionManifestTest,ExperimentalPermission)350 TEST_F(ExtensionManifestTest, ExperimentalPermission) {
351 LoadAndExpectError("experimental.json", errors::kExperimentalFlagRequired);
352 CommandLine old_command_line = *CommandLine::ForCurrentProcess();
353 CommandLine::ForCurrentProcess()->AppendSwitch(
354 switches::kEnableExperimentalExtensionApis);
355 LoadAndExpectSuccess("experimental.json");
356 *CommandLine::ForCurrentProcess() = old_command_line;
357 }
358
TEST_F(ExtensionManifestTest,DevToolsExtensions)359 TEST_F(ExtensionManifestTest, DevToolsExtensions) {
360 LoadAndExpectError("devtools_extension_no_permissions.json",
361 errors::kDevToolsExperimental);
362 LoadAndExpectError("devtools_extension_url_invalid_type.json",
363 errors::kInvalidDevToolsPage);
364
365 CommandLine old_command_line = *CommandLine::ForCurrentProcess();
366 CommandLine::ForCurrentProcess()->AppendSwitch(
367 switches::kEnableExperimentalExtensionApis);
368
369 scoped_refptr<Extension> extension;
370 extension = LoadAndExpectSuccess("devtools_extension.json");
371 EXPECT_EQ(extension->url().spec() + "devtools.html",
372 extension->devtools_url().spec());
373 EXPECT_TRUE(extension->HasEffectiveAccessToAllHosts());
374
375 *CommandLine::ForCurrentProcess() = old_command_line;
376 }
377
TEST_F(ExtensionManifestTest,Sidebar)378 TEST_F(ExtensionManifestTest, Sidebar) {
379 LoadAndExpectError("sidebar.json",
380 errors::kExperimentalFlagRequired);
381
382 CommandLine old_command_line = *CommandLine::ForCurrentProcess();
383 CommandLine::ForCurrentProcess()->AppendSwitch(
384 switches::kEnableExperimentalExtensionApis);
385
386 LoadAndExpectError("sidebar_no_permissions.json",
387 errors::kSidebarExperimental);
388
389 LoadAndExpectError("sidebar_icon_empty.json",
390 errors::kInvalidSidebarDefaultIconPath);
391 LoadAndExpectError("sidebar_icon_invalid_type.json",
392 errors::kInvalidSidebarDefaultIconPath);
393 LoadAndExpectError("sidebar_page_empty.json",
394 errors::kInvalidSidebarDefaultPage);
395 LoadAndExpectError("sidebar_page_invalid_type.json",
396 errors::kInvalidSidebarDefaultPage);
397 LoadAndExpectError("sidebar_title_invalid_type.json",
398 errors::kInvalidSidebarDefaultTitle);
399
400 scoped_refptr<Extension> extension(LoadAndExpectSuccess("sidebar.json"));
401 ASSERT_TRUE(extension->sidebar_defaults() != NULL);
402 EXPECT_EQ(extension->sidebar_defaults()->default_title(),
403 ASCIIToUTF16("Default title"));
404 EXPECT_EQ(extension->sidebar_defaults()->default_icon_path(),
405 "icon.png");
406 EXPECT_EQ(extension->url().spec() + "sidebar.html",
407 extension->sidebar_defaults()->default_page().spec());
408
409 *CommandLine::ForCurrentProcess() = old_command_line;
410 }
411
TEST_F(ExtensionManifestTest,DisallowHybridApps)412 TEST_F(ExtensionManifestTest, DisallowHybridApps) {
413 LoadAndExpectError("disallow_hybrid_1.json",
414 ExtensionErrorUtils::FormatErrorMessage(
415 errors::kHostedAppsCannotIncludeExtensionFeatures,
416 keys::kBrowserAction));
417 LoadAndExpectError("disallow_hybrid_2.json",
418 errors::kBackgroundPermissionNeeded);
419 }
420
TEST_F(ExtensionManifestTest,OptionsPageInApps)421 TEST_F(ExtensionManifestTest, OptionsPageInApps) {
422 scoped_refptr<Extension> extension;
423
424 // Allow options page with absolute URL in hosed apps.
425 extension = LoadAndExpectSuccess("hosted_app_absolute_options.json");
426 EXPECT_STREQ("http",
427 extension->options_url().scheme().c_str());
428 EXPECT_STREQ("example.com",
429 extension->options_url().host().c_str());
430 EXPECT_STREQ("options.html",
431 extension->options_url().ExtractFileName().c_str());
432
433 // Forbid options page with relative URL in hosted apps.
434 LoadAndExpectError("hosted_app_relative_options.json",
435 errors::kInvalidOptionsPageInHostedApp);
436
437 // Forbid options page with non-(http|https) scheme in hosted app.
438 LoadAndExpectError("hosted_app_file_options.json",
439 errors::kInvalidOptionsPageInHostedApp);
440
441 // Forbid absolute URL for options page in packaged apps.
442 LoadAndExpectError("packaged_app_absolute_options.json",
443 errors::kInvalidOptionsPageExpectUrlInPackage);
444 }
445
TEST_F(ExtensionManifestTest,AllowUnrecognizedPermissions)446 TEST_F(ExtensionManifestTest, AllowUnrecognizedPermissions) {
447 std::string error;
448 scoped_ptr<DictionaryValue> manifest(
449 LoadManifestFile("valid_app.json", &error));
450 ASSERT_TRUE(manifest.get());
451
452 ListValue *permissions = new ListValue();
453 manifest->Set(keys::kPermissions, permissions);
454 for (size_t i = 0; i < Extension::kNumPermissions; i++) {
455 const char* name = Extension::kPermissions[i].name;
456 StringValue* p = new StringValue(name);
457 permissions->Clear();
458 permissions->Append(p);
459 std::string message_name = base::StringPrintf("permission-%s", name);
460
461 // Extensions are allowed to contain unrecognized API permissions,
462 // so there shouldn't be any errors.
463 scoped_refptr<Extension> extension;
464 extension = LoadAndExpectSuccess(manifest.get(), message_name);
465 }
466 }
467
TEST_F(ExtensionManifestTest,NormalizeIconPaths)468 TEST_F(ExtensionManifestTest, NormalizeIconPaths) {
469 scoped_refptr<Extension> extension(
470 LoadAndExpectSuccess("normalize_icon_paths.json"));
471 EXPECT_EQ("16.png",
472 extension->icons().Get(16, ExtensionIconSet::MATCH_EXACTLY));
473 EXPECT_EQ("48.png",
474 extension->icons().Get(48, ExtensionIconSet::MATCH_EXACTLY));
475 }
476
TEST_F(ExtensionManifestTest,DisallowMultipleUISurfaces)477 TEST_F(ExtensionManifestTest, DisallowMultipleUISurfaces) {
478 LoadAndExpectError("multiple_ui_surfaces_1.json", errors::kOneUISurfaceOnly);
479 LoadAndExpectError("multiple_ui_surfaces_2.json", errors::kOneUISurfaceOnly);
480 LoadAndExpectError("multiple_ui_surfaces_3.json", errors::kOneUISurfaceOnly);
481 }
482
TEST_F(ExtensionManifestTest,ParseHomepageURLs)483 TEST_F(ExtensionManifestTest, ParseHomepageURLs) {
484 scoped_refptr<Extension> extension(
485 LoadAndExpectSuccess("homepage_valid.json"));
486 LoadAndExpectError("homepage_empty.json",
487 extension_manifest_errors::kInvalidHomepageURL);
488 LoadAndExpectError("homepage_invalid.json",
489 extension_manifest_errors::kInvalidHomepageURL);
490 }
491
TEST_F(ExtensionManifestTest,GetHomepageURL)492 TEST_F(ExtensionManifestTest, GetHomepageURL) {
493 scoped_refptr<Extension> extension(
494 LoadAndExpectSuccess("homepage_valid.json"));
495 EXPECT_EQ(GURL("http://foo.com#bar"), extension->GetHomepageURL());
496
497 // The Google Gallery URL ends with the id, which depends on the path, which
498 // can be different in testing, so we just check the part before id.
499 extension = LoadAndExpectSuccess("homepage_google_hosted.json");
500 EXPECT_TRUE(StartsWithASCII(extension->GetHomepageURL().spec(),
501 "https://chrome.google.com/webstore/detail/",
502 false));
503
504 extension = LoadAndExpectSuccess("homepage_externally_hosted.json");
505 EXPECT_EQ(GURL(), extension->GetHomepageURL());
506 }
507
TEST_F(ExtensionManifestTest,DefaultPathForExtent)508 TEST_F(ExtensionManifestTest, DefaultPathForExtent) {
509 scoped_refptr<Extension> extension(
510 LoadAndExpectSuccess("default_path_for_extent.json"));
511
512 ASSERT_EQ(1u, extension->web_extent().patterns().size());
513 EXPECT_EQ("/*", extension->web_extent().patterns()[0].path());
514 EXPECT_TRUE(extension->web_extent().ContainsURL(
515 GURL("http://www.google.com/monkey")));
516 }
517
TEST_F(ExtensionManifestTest,DefaultLocale)518 TEST_F(ExtensionManifestTest, DefaultLocale) {
519 LoadAndExpectError("default_locale_invalid.json",
520 extension_manifest_errors::kInvalidDefaultLocale);
521
522 scoped_refptr<Extension> extension(
523 LoadAndExpectSuccess("default_locale_valid.json"));
524 EXPECT_EQ("de-AT", extension->default_locale());
525 }
526
TEST_F(ExtensionManifestTest,TtsProvider)527 TEST_F(ExtensionManifestTest, TtsProvider) {
528 LoadAndExpectError("tts_provider_invalid_1.json",
529 extension_manifest_errors::kInvalidTts);
530 LoadAndExpectError("tts_provider_invalid_2.json",
531 extension_manifest_errors::kInvalidTtsVoices);
532 LoadAndExpectError("tts_provider_invalid_3.json",
533 extension_manifest_errors::kInvalidTtsVoices);
534 LoadAndExpectError("tts_provider_invalid_4.json",
535 extension_manifest_errors::kInvalidTtsVoicesVoiceName);
536 LoadAndExpectError("tts_provider_invalid_5.json",
537 extension_manifest_errors::kInvalidTtsVoicesLocale);
538 LoadAndExpectError("tts_provider_invalid_6.json",
539 extension_manifest_errors::kInvalidTtsVoicesLocale);
540 LoadAndExpectError("tts_provider_invalid_7.json",
541 extension_manifest_errors::kInvalidTtsVoicesGender);
542
543 scoped_refptr<Extension> extension(
544 LoadAndExpectSuccess("tts_provider_valid.json"));
545
546 ASSERT_EQ(1u, extension->tts_voices().size());
547 EXPECT_EQ("name", extension->tts_voices()[0].voice_name);
548 EXPECT_EQ("en-US", extension->tts_voices()[0].locale);
549 EXPECT_EQ("female", extension->tts_voices()[0].gender);
550 }
551
TEST_F(ExtensionManifestTest,ForbidPortsInPermissions)552 TEST_F(ExtensionManifestTest, ForbidPortsInPermissions) {
553 // Loading as a user would shoud not trigger an error.
554 LoadAndExpectSuccess("forbid_ports_in_permissions.json");
555
556 // Ideally, loading as a developer would give an error.
557 // To ensure that we do not error out on a valid permission
558 // in a future version of chrome, validation is to loose
559 // to flag this case.
560 LoadStrictAndExpectSuccess("forbid_ports_in_permissions.json");
561 }
562
TEST_F(ExtensionManifestTest,IsolatedApps)563 TEST_F(ExtensionManifestTest, IsolatedApps) {
564 // Requires --enable-experimental-app-manifests
565 scoped_refptr<Extension> extension(
566 LoadAndExpectSuccess("isolated_app_valid.json"));
567 EXPECT_FALSE(extension->is_storage_isolated());
568
569 CommandLine old_command_line = *CommandLine::ForCurrentProcess();
570 CommandLine::ForCurrentProcess()->AppendSwitch(
571 switches::kEnableExperimentalAppManifests);
572 scoped_refptr<Extension> extension2(
573 LoadAndExpectSuccess("isolated_app_valid.json"));
574 EXPECT_TRUE(extension2->is_storage_isolated());
575 *CommandLine::ForCurrentProcess() = old_command_line;
576 }
577
578
TEST_F(ExtensionManifestTest,FileBrowserHandlers)579 TEST_F(ExtensionManifestTest, FileBrowserHandlers) {
580 LoadAndExpectError("filebrowser_invalid_actions_1.json",
581 errors::kInvalidFileBrowserHandler);
582 LoadAndExpectError("filebrowser_invalid_actions_2.json",
583 errors::kInvalidFileBrowserHandler);
584 LoadAndExpectError("filebrowser_invalid_action_id.json",
585 errors::kInvalidPageActionId);
586 LoadAndExpectError("filebrowser_invalid_action_title.json",
587 errors::kInvalidPageActionDefaultTitle);
588 LoadAndExpectError("filebrowser_invalid_action_id.json",
589 errors::kInvalidPageActionId);
590 LoadAndExpectError("filebrowser_invalid_file_filters_1.json",
591 errors::kInvalidFileFiltersList);
592 LoadAndExpectError("filebrowser_invalid_file_filters_2.json",
593 ExtensionErrorUtils::FormatErrorMessage(
594 errors::kInvalidFileFilterValue, base::IntToString(0)));
595 LoadAndExpectError("filebrowser_invalid_file_filters_url.json",
596 ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidURLPatternError,
597 "http:*.html"));
598
599 scoped_refptr<Extension> extension(
600 LoadAndExpectSuccess("filebrowser_valid.json"));
601 ASSERT_TRUE(extension->file_browser_handlers() != NULL);
602 ASSERT_EQ(extension->file_browser_handlers()->size(), 1U);
603 const FileBrowserHandler* action =
604 extension->file_browser_handlers()->at(0).get();
605 EXPECT_EQ(action->title(), "Default title");
606 EXPECT_EQ(action->icon_path(), "icon.png");
607 const FileBrowserHandler::PatternList& patterns = action->file_url_patterns();
608 ASSERT_EQ(patterns.size(), 1U);
609 ASSERT_TRUE(action->MatchesURL(
610 GURL("filesystem:chrome-extension://foo/local/test.txt")));
611 }
612