extension_manifests_unittest.cc revision ddb351dbec246cf1fab5ec20d2d5520909041de1
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
24namespace errors = extension_manifest_errors;
25namespace keys = extension_manifest_keys;
26
27class ExtensionManifestTest : public testing::Test {
28 public:
29  ExtensionManifestTest() : enable_apps_(true) {}
30
31 protected:
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
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
59  scoped_refptr<Extension> LoadExtension(const std::string& name,
60                                         std::string* error) {
61    return LoadExtensionWithLocation(name, Extension::INTERNAL, false, error);
62  }
63
64  scoped_refptr<Extension> LoadExtensionStrict(const std::string& name,
65                                               std::string* error) {
66    return LoadExtensionWithLocation(name, Extension::INTERNAL, true, error);
67  }
68
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
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
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
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
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
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
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
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
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
148TEST_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
159TEST_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
216TEST_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
252TEST_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
279TEST_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
296TEST_F(ExtensionManifestTest, ChromeURLPermissionInvalid) {
297  LoadAndExpectError("permission_chrome_url_invalid.json",
298      errors::kInvalidPermissionScheme);
299}
300
301TEST_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
314TEST_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
350TEST_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
359TEST_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
378TEST_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
412TEST_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
421TEST_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
446TEST_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
468TEST_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
477TEST_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
483TEST_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
492TEST_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
508TEST_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
518TEST_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
527TEST_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
552TEST_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
563TEST_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
579TEST_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