• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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