1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/command_line.h"
6#include "base/i18n/rtl.h"
7#include "base/path_service.h"
8#include "base/strings/utf_string_conversions.h"
9#include "chrome/common/chrome_paths.h"
10#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
11#include "components/crx_file/id_util.h"
12#include "extensions/common/extension.h"
13#include "extensions/common/manifest_constants.h"
14#include "extensions/common/manifest_handlers/options_page_info.h"
15#include "extensions/common/switches.h"
16#include "testing/gtest/include/gtest/gtest.h"
17#include "ui/base/l10n/l10n_util.h"
18
19namespace extensions {
20
21namespace {
22
23// The ID of test manifests requiring whitelisting.
24const char kWhitelistID[] = "lmadimbbgapmngbiclpjjngmdickadpl";
25
26}  // namespace
27
28namespace errors = manifest_errors;
29namespace keys = manifest_keys;
30
31class InitValueManifestTest : public ChromeManifestTest {
32};
33
34TEST_F(InitValueManifestTest, InitFromValueInvalid) {
35  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
36      extensions::switches::kWhitelistedExtensionID, kWhitelistID);
37  Testcase testcases[] = {
38    Testcase("init_invalid_version_missing.json", errors::kInvalidVersion),
39    Testcase("init_invalid_version_invalid.json", errors::kInvalidVersion),
40    Testcase("init_invalid_name_missing.json", errors::kInvalidName),
41    Testcase("init_invalid_name_invalid.json", errors::kInvalidName),
42    Testcase("init_invalid_description_invalid.json",
43             errors::kInvalidDescription),
44    Testcase("init_invalid_icons_invalid.json", errors::kInvalidIcons),
45    Testcase("init_invalid_icons_path_invalid.json", errors::kInvalidIconPath),
46    Testcase("init_invalid_launcher_page_invalid.json",
47             errors::kInvalidLauncherPage),
48    Testcase("init_invalid_launcher_page_page_missing.json",
49             errors::kLauncherPagePageRequired),
50    Testcase("init_invalid_launcher_page_page_invalid.json",
51             errors::kInvalidLauncherPagePage),
52    Testcase("init_invalid_script_invalid.json",
53             errors::kInvalidContentScriptsList),
54    Testcase("init_invalid_script_item_invalid.json",
55             errors::kInvalidContentScript),
56    Testcase("init_invalid_script_matches_missing.json",
57             errors::kInvalidMatches),
58    Testcase("init_invalid_script_matches_invalid.json",
59             errors::kInvalidMatches),
60    Testcase("init_invalid_script_matches_empty.json",
61             errors::kInvalidMatchCount),
62    Testcase("init_invalid_script_match_item_invalid.json",
63             errors::kInvalidMatch),
64    Testcase("init_invalid_script_match_item_invalid_2.json",
65             errors::kInvalidMatch),
66    Testcase("init_invalid_script_files_missing.json", errors::kMissingFile),
67    Testcase("init_invalid_files_js_invalid.json", errors::kInvalidJsList),
68    Testcase("init_invalid_files_empty.json", errors::kMissingFile),
69    Testcase("init_invalid_files_js_empty_css_missing.json",
70             errors::kMissingFile),
71    Testcase("init_invalid_files_js_item_invalid.json", errors::kInvalidJs),
72    Testcase("init_invalid_files_css_invalid.json", errors::kInvalidCssList),
73    Testcase("init_invalid_files_css_item_invalid.json", errors::kInvalidCss),
74    Testcase("init_invalid_permissions_invalid.json",
75             errors::kInvalidPermissions),
76    Testcase("init_invalid_permissions_item_invalid.json",
77             errors::kInvalidPermission),
78    Testcase("init_invalid_page_actions_multi.json",
79             errors::kInvalidPageActionsListSize),
80    Testcase("init_invalid_options_url_invalid.json",
81             errors::kInvalidOptionsPage),
82    Testcase("init_invalid_locale_invalid.json", errors::kInvalidDefaultLocale),
83    Testcase("init_invalid_locale_empty.json", errors::kInvalidDefaultLocale),
84    Testcase("init_invalid_min_chrome_invalid.json",
85             errors::kInvalidMinimumChromeVersion),
86    Testcase("init_invalid_chrome_version_too_low.json",
87             errors::kChromeVersionTooLow),
88    Testcase("init_invalid_short_name_empty.json",
89             errors::kInvalidShortName),
90    Testcase("init_invalid_short_name_type.json",
91             errors::kInvalidShortName),
92  };
93
94  RunTestcases(testcases, arraysize(testcases),
95               EXPECT_TYPE_ERROR);
96}
97
98TEST_F(InitValueManifestTest, InitFromValueValid) {
99  scoped_refptr<Extension> extension(LoadAndExpectSuccess(
100      "init_valid_minimal.json"));
101
102  base::FilePath path;
103  PathService::Get(chrome::DIR_TEST_DATA, &path);
104  path = path.AppendASCII("extensions");
105
106  EXPECT_TRUE(crx_file::id_util::IdIsValid(extension->id()));
107  EXPECT_EQ("1.0.0.0", extension->VersionString());
108  EXPECT_EQ("my extension", extension->name());
109  EXPECT_EQ(extension->name(), extension->short_name());
110  EXPECT_EQ(extension->id(), extension->url().host());
111  EXPECT_EQ(extension->path(), path);
112  EXPECT_EQ(path, extension->path());
113
114  // Test permissions scheme.
115  // We allow unknown API permissions, so this will be valid until we better
116  // distinguish between API and host permissions.
117  LoadAndExpectSuccess("init_valid_permissions.json");
118
119  // Test with an options page.
120  extension = LoadAndExpectSuccess("init_valid_options.json");
121  EXPECT_EQ("chrome-extension",
122            OptionsPageInfo::GetOptionsPage(extension.get()).scheme());
123  EXPECT_EQ("/options.html",
124            OptionsPageInfo::GetOptionsPage(extension.get()).path());
125
126  // Test optional short_name field.
127  extension = LoadAndExpectSuccess("init_valid_short_name.json");
128  EXPECT_EQ("a very descriptive extension name", extension->name());
129  EXPECT_EQ("concise name", extension->short_name());
130
131  Testcase testcases[] = {
132    // Test that an empty list of page actions does not stop a browser action
133    // from being loaded.
134    Testcase("init_valid_empty_page_actions.json"),
135
136    // Test with a minimum_chrome_version.
137    Testcase("init_valid_minimum_chrome.json"),
138
139    // Test a hosted app with a minimum_chrome_version.
140    Testcase("init_valid_app_minimum_chrome.json"),
141
142    // Test a hosted app with a requirements section.
143    Testcase("init_valid_app_requirements.json"),
144
145    // Verify empty permission settings are considered valid.
146    Testcase("init_valid_permissions_empty.json"),
147
148    // We allow unknown API permissions, so this will be valid until we better
149    // distinguish between API and host permissions.
150    Testcase("init_valid_permissions_unknown.json")
151  };
152
153  RunTestcases(testcases, arraysize(testcases),
154               EXPECT_TYPE_SUCCESS);
155}
156
157TEST_F(InitValueManifestTest, InitFromValueValidNameInRTL) {
158  std::string locale = l10n_util::GetApplicationLocale("");
159  base::i18n::SetICUDefaultLocale("he");
160
161  // No strong RTL characters in name.
162  scoped_refptr<Extension> extension(LoadAndExpectSuccess(
163      "init_valid_name_no_rtl.json"));
164
165  base::string16 localized_name(base::ASCIIToUTF16("Dictionary (by Google)"));
166  base::i18n::AdjustStringForLocaleDirection(&localized_name);
167  EXPECT_EQ(localized_name, base::UTF8ToUTF16(extension->name()));
168
169  // Strong RTL characters in name.
170  extension = LoadAndExpectSuccess("init_valid_name_strong_rtl.json");
171
172  localized_name = base::WideToUTF16(L"Dictionary (\x05D1\x05D2" L" Google)");
173  base::i18n::AdjustStringForLocaleDirection(&localized_name);
174  EXPECT_EQ(localized_name, base::UTF8ToUTF16(extension->name()));
175
176  // Reset locale.
177  base::i18n::SetICUDefaultLocale(locale);
178}
179
180}  // namespace extensions
181