• 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/file_path.h"
6 #include "base/file_util.h"
7 #include "base/memory/linked_ptr.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/memory/scoped_temp_dir.h"
10 #include "base/path_service.h"
11 #include "base/values.h"
12 #include "chrome/common/chrome_paths.h"
13 #include "chrome/common/extensions/extension.h"
14 #include "chrome/common/extensions/extension_constants.h"
15 #include "chrome/common/extensions/extension_l10n_util.h"
16 #include "chrome/common/extensions/extension_message_bundle.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "ui/base/l10n/l10n_util.h"
19 
20 namespace errors = extension_manifest_errors;
21 namespace keys = extension_manifest_keys;
22 
23 namespace {
24 
TEST(ExtensionL10nUtil,GetValidLocalesEmptyLocaleFolder)25 TEST(ExtensionL10nUtil, GetValidLocalesEmptyLocaleFolder) {
26   ScopedTempDir temp;
27   ASSERT_TRUE(temp.CreateUniqueTempDir());
28 
29   FilePath src_path = temp.path().Append(Extension::kLocaleFolder);
30   ASSERT_TRUE(file_util::CreateDirectory(src_path));
31 
32   std::string error;
33   std::set<std::string> locales;
34   EXPECT_FALSE(extension_l10n_util::GetValidLocales(src_path,
35                                                     &locales,
36                                                     &error));
37 
38   EXPECT_TRUE(locales.empty());
39 }
40 
TEST(ExtensionL10nUtil,GetValidLocalesWithValidLocaleNoMessagesFile)41 TEST(ExtensionL10nUtil, GetValidLocalesWithValidLocaleNoMessagesFile) {
42   ScopedTempDir temp;
43   ASSERT_TRUE(temp.CreateUniqueTempDir());
44 
45   FilePath src_path = temp.path().Append(Extension::kLocaleFolder);
46   ASSERT_TRUE(file_util::CreateDirectory(src_path));
47   ASSERT_TRUE(file_util::CreateDirectory(src_path.AppendASCII("sr")));
48 
49   std::string error;
50   std::set<std::string> locales;
51   EXPECT_FALSE(extension_l10n_util::GetValidLocales(src_path,
52                                                     &locales,
53                                                     &error));
54 
55   EXPECT_TRUE(locales.empty());
56 }
57 
TEST(ExtensionL10nUtil,GetValidLocalesWithUnsupportedLocale)58 TEST(ExtensionL10nUtil, GetValidLocalesWithUnsupportedLocale) {
59   ScopedTempDir temp;
60   ASSERT_TRUE(temp.CreateUniqueTempDir());
61 
62   FilePath src_path = temp.path().Append(Extension::kLocaleFolder);
63   ASSERT_TRUE(file_util::CreateDirectory(src_path));
64   // Supported locale.
65   FilePath locale_1 = src_path.AppendASCII("sr");
66   ASSERT_TRUE(file_util::CreateDirectory(locale_1));
67   std::string data("whatever");
68   ASSERT_TRUE(file_util::WriteFile(
69       locale_1.Append(Extension::kMessagesFilename),
70       data.c_str(), data.length()));
71   // Unsupported locale.
72   ASSERT_TRUE(file_util::CreateDirectory(src_path.AppendASCII("xxx_yyy")));
73 
74   std::string error;
75   std::set<std::string> locales;
76   EXPECT_TRUE(extension_l10n_util::GetValidLocales(src_path,
77                                                    &locales,
78                                                    &error));
79 
80   EXPECT_FALSE(locales.empty());
81   EXPECT_TRUE(locales.find("sr") != locales.end());
82   EXPECT_FALSE(locales.find("xxx_yyy") != locales.end());
83 }
84 
TEST(ExtensionL10nUtil,GetValidLocalesWithValidLocalesAndMessagesFile)85 TEST(ExtensionL10nUtil, GetValidLocalesWithValidLocalesAndMessagesFile) {
86   FilePath install_dir;
87   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
88   install_dir = install_dir.AppendASCII("extensions")
89       .AppendASCII("good")
90       .AppendASCII("Extensions")
91       .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
92       .AppendASCII("1.0.0.0")
93       .Append(Extension::kLocaleFolder);
94 
95   std::string error;
96   std::set<std::string> locales;
97   EXPECT_TRUE(extension_l10n_util::GetValidLocales(install_dir,
98                                                    &locales,
99                                                    &error));
100   EXPECT_EQ(3U, locales.size());
101   EXPECT_TRUE(locales.find("sr") != locales.end());
102   EXPECT_TRUE(locales.find("en") != locales.end());
103   EXPECT_TRUE(locales.find("en_US") != locales.end());
104 }
105 
TEST(ExtensionL10nUtil,LoadMessageCatalogsValidFallback)106 TEST(ExtensionL10nUtil, LoadMessageCatalogsValidFallback) {
107   FilePath install_dir;
108   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
109   install_dir = install_dir.AppendASCII("extensions")
110       .AppendASCII("good")
111       .AppendASCII("Extensions")
112       .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
113       .AppendASCII("1.0.0.0")
114       .Append(Extension::kLocaleFolder);
115 
116   std::string error;
117   std::set<std::string> locales;
118   EXPECT_TRUE(extension_l10n_util::GetValidLocales(install_dir,
119                                                    &locales,
120                                                    &error));
121 
122   scoped_ptr<ExtensionMessageBundle> bundle(
123       extension_l10n_util::LoadMessageCatalogs(
124           install_dir, "sr", "en_US", locales, &error));
125   ASSERT_FALSE(NULL == bundle.get());
126   EXPECT_TRUE(error.empty());
127   EXPECT_EQ("Color", bundle->GetL10nMessage("color"));
128   EXPECT_EQ("Not in the US or GB.", bundle->GetL10nMessage("not_in_US_or_GB"));
129 }
130 
TEST(ExtensionL10nUtil,LoadMessageCatalogsMissingFiles)131 TEST(ExtensionL10nUtil, LoadMessageCatalogsMissingFiles) {
132   ScopedTempDir temp;
133   ASSERT_TRUE(temp.CreateUniqueTempDir());
134 
135   FilePath src_path = temp.path().Append(Extension::kLocaleFolder);
136   ASSERT_TRUE(file_util::CreateDirectory(src_path));
137 
138   std::set<std::string> valid_locales;
139   valid_locales.insert("sr");
140   valid_locales.insert("en");
141   std::string error;
142   EXPECT_TRUE(NULL == extension_l10n_util::LoadMessageCatalogs(src_path,
143                                                                "en",
144                                                                "sr",
145                                                                valid_locales,
146                                                                &error));
147   EXPECT_FALSE(error.empty());
148 }
149 
TEST(ExtensionL10nUtil,LoadMessageCatalogsBadJSONFormat)150 TEST(ExtensionL10nUtil, LoadMessageCatalogsBadJSONFormat) {
151   ScopedTempDir temp;
152   ASSERT_TRUE(temp.CreateUniqueTempDir());
153 
154   FilePath src_path = temp.path().Append(Extension::kLocaleFolder);
155   ASSERT_TRUE(file_util::CreateDirectory(src_path));
156 
157   FilePath locale = src_path.AppendASCII("sr");
158   ASSERT_TRUE(file_util::CreateDirectory(locale));
159 
160   std::string data = "{ \"name\":";
161   ASSERT_TRUE(
162       file_util::WriteFile(locale.Append(Extension::kMessagesFilename),
163                            data.c_str(), data.length()));
164 
165   std::set<std::string> valid_locales;
166   valid_locales.insert("sr");
167   valid_locales.insert("en_US");
168   std::string error;
169   EXPECT_TRUE(NULL == extension_l10n_util::LoadMessageCatalogs(src_path,
170                                                               "en_US",
171                                                               "sr",
172                                                               valid_locales,
173                                                               &error));
174   EXPECT_EQ("Line: 1, column: 10, Syntax error.", error);
175 }
176 
TEST(ExtensionL10nUtil,LoadMessageCatalogsDuplicateKeys)177 TEST(ExtensionL10nUtil, LoadMessageCatalogsDuplicateKeys) {
178   ScopedTempDir temp;
179   ASSERT_TRUE(temp.CreateUniqueTempDir());
180 
181   FilePath src_path = temp.path().Append(Extension::kLocaleFolder);
182   ASSERT_TRUE(file_util::CreateDirectory(src_path));
183 
184   FilePath locale_1 = src_path.AppendASCII("en");
185   ASSERT_TRUE(file_util::CreateDirectory(locale_1));
186 
187   std::string data =
188     "{ \"name\": { \"message\": \"something\" }, "
189     "\"name\": { \"message\": \"something else\" } }";
190   ASSERT_TRUE(
191       file_util::WriteFile(locale_1.Append(Extension::kMessagesFilename),
192                            data.c_str(), data.length()));
193 
194   FilePath locale_2 = src_path.AppendASCII("sr");
195   ASSERT_TRUE(file_util::CreateDirectory(locale_2));
196 
197   ASSERT_TRUE(
198       file_util::WriteFile(locale_2.Append(Extension::kMessagesFilename),
199                            data.c_str(), data.length()));
200 
201   std::set<std::string> valid_locales;
202   valid_locales.insert("sr");
203   valid_locales.insert("en");
204   std::string error;
205   // JSON parser hides duplicates. We are going to get only one key/value
206   // pair at the end.
207   scoped_ptr<ExtensionMessageBundle> message_bundle(
208       extension_l10n_util::LoadMessageCatalogs(src_path,
209                                                "en",
210                                                "sr",
211                                                valid_locales,
212                                                &error));
213   EXPECT_TRUE(NULL != message_bundle.get());
214   EXPECT_TRUE(error.empty());
215 }
216 
217 // Caller owns the returned object.
CreateManifestBundle()218 ExtensionMessageBundle* CreateManifestBundle() {
219   linked_ptr<DictionaryValue> catalog(new DictionaryValue);
220 
221   DictionaryValue* name_tree = new DictionaryValue();
222   name_tree->SetString("message", "name");
223   catalog->Set("name", name_tree);
224 
225   DictionaryValue* description_tree = new DictionaryValue();
226   description_tree->SetString("message", "description");
227   catalog->Set("description", description_tree);
228 
229   DictionaryValue* action_title_tree = new DictionaryValue();
230   action_title_tree->SetString("message", "action title");
231   catalog->Set("title", action_title_tree);
232 
233   DictionaryValue* omnibox_keyword_tree = new DictionaryValue();
234   omnibox_keyword_tree->SetString("message", "omnibox keyword");
235   catalog->Set("omnibox_keyword", omnibox_keyword_tree);
236 
237   DictionaryValue* file_handler_title_tree = new DictionaryValue();
238   file_handler_title_tree->SetString("message", "file handler title");
239   catalog->Set("file_handler_title", file_handler_title_tree);
240 
241   std::vector<linked_ptr<DictionaryValue> > catalogs;
242   catalogs.push_back(catalog);
243 
244   std::string error;
245   ExtensionMessageBundle* bundle =
246       ExtensionMessageBundle::Create(catalogs, &error);
247   EXPECT_TRUE(bundle);
248   EXPECT_TRUE(error.empty());
249 
250   return bundle;
251 }
252 
TEST(ExtensionL10nUtil,LocalizeEmptyManifest)253 TEST(ExtensionL10nUtil, LocalizeEmptyManifest) {
254   DictionaryValue manifest;
255   std::string error;
256   scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle());
257 
258   EXPECT_FALSE(
259       extension_l10n_util::LocalizeManifest(*messages, &manifest, &error));
260   EXPECT_EQ(errors::kInvalidName, error);
261 }
262 
TEST(ExtensionL10nUtil,LocalizeManifestWithoutNameMsgAndEmptyDescription)263 TEST(ExtensionL10nUtil, LocalizeManifestWithoutNameMsgAndEmptyDescription) {
264   DictionaryValue manifest;
265   manifest.SetString(keys::kName, "no __MSG");
266   std::string error;
267   scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle());
268 
269   EXPECT_TRUE(
270       extension_l10n_util::LocalizeManifest(*messages, &manifest, &error));
271 
272   std::string result;
273   ASSERT_TRUE(manifest.GetString(keys::kName, &result));
274   EXPECT_EQ("no __MSG", result);
275 
276   EXPECT_FALSE(manifest.HasKey(keys::kDescription));
277 
278   EXPECT_TRUE(error.empty());
279 }
280 
TEST(ExtensionL10nUtil,LocalizeManifestWithNameMsgAndEmptyDescription)281 TEST(ExtensionL10nUtil, LocalizeManifestWithNameMsgAndEmptyDescription) {
282   DictionaryValue manifest;
283   manifest.SetString(keys::kName, "__MSG_name__");
284   std::string error;
285   scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle());
286 
287   EXPECT_TRUE(
288       extension_l10n_util::LocalizeManifest(*messages, &manifest, &error));
289 
290   std::string result;
291   ASSERT_TRUE(manifest.GetString(keys::kName, &result));
292   EXPECT_EQ("name", result);
293 
294   EXPECT_FALSE(manifest.HasKey(keys::kDescription));
295 
296   EXPECT_TRUE(error.empty());
297 }
298 
TEST(ExtensionL10nUtil,LocalizeManifestWithBadNameMsg)299 TEST(ExtensionL10nUtil, LocalizeManifestWithBadNameMsg) {
300   DictionaryValue manifest;
301   manifest.SetString(keys::kName, "__MSG_name_is_bad__");
302   manifest.SetString(keys::kDescription, "__MSG_description__");
303   std::string error;
304   scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle());
305 
306   EXPECT_FALSE(
307       extension_l10n_util::LocalizeManifest(*messages, &manifest, &error));
308 
309   std::string result;
310   ASSERT_TRUE(manifest.GetString(keys::kName, &result));
311   EXPECT_EQ("__MSG_name_is_bad__", result);
312 
313   ASSERT_TRUE(manifest.GetString(keys::kDescription, &result));
314   EXPECT_EQ("__MSG_description__", result);
315 
316   EXPECT_EQ("Variable __MSG_name_is_bad__ used but not defined.", error);
317 }
318 
TEST(ExtensionL10nUtil,LocalizeManifestWithNameDescriptionDefaultTitleMsgs)319 TEST(ExtensionL10nUtil, LocalizeManifestWithNameDescriptionDefaultTitleMsgs) {
320   DictionaryValue manifest;
321   manifest.SetString(keys::kName, "__MSG_name__");
322   manifest.SetString(keys::kDescription, "__MSG_description__");
323   std::string action_title(keys::kBrowserAction);
324   action_title.append(".");
325   action_title.append(keys::kPageActionDefaultTitle);
326   manifest.SetString(action_title, "__MSG_title__");
327 
328   std::string error;
329   scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle());
330 
331   EXPECT_TRUE(
332       extension_l10n_util::LocalizeManifest(*messages, &manifest, &error));
333 
334   std::string result;
335   ASSERT_TRUE(manifest.GetString(keys::kName, &result));
336   EXPECT_EQ("name", result);
337 
338   ASSERT_TRUE(manifest.GetString(keys::kDescription, &result));
339   EXPECT_EQ("description", result);
340 
341   ASSERT_TRUE(manifest.GetString(action_title, &result));
342   EXPECT_EQ("action title", result);
343 
344   EXPECT_TRUE(error.empty());
345 }
346 
TEST(ExtensionL10nUtil,LocalizeManifestWithNameDescriptionOmniboxMsgs)347 TEST(ExtensionL10nUtil, LocalizeManifestWithNameDescriptionOmniboxMsgs) {
348   DictionaryValue manifest;
349   manifest.SetString(keys::kName, "__MSG_name__");
350   manifest.SetString(keys::kDescription, "__MSG_description__");
351   manifest.SetString(keys::kOmniboxKeyword, "__MSG_omnibox_keyword__");
352 
353   std::string error;
354   scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle());
355 
356   EXPECT_TRUE(
357       extension_l10n_util::LocalizeManifest(*messages, &manifest, &error));
358 
359   std::string result;
360   ASSERT_TRUE(manifest.GetString(keys::kName, &result));
361   EXPECT_EQ("name", result);
362 
363   ASSERT_TRUE(manifest.GetString(keys::kDescription, &result));
364   EXPECT_EQ("description", result);
365 
366   ASSERT_TRUE(manifest.GetString(keys::kOmniboxKeyword, &result));
367   EXPECT_EQ("omnibox keyword", result);
368 
369   EXPECT_TRUE(error.empty());
370 }
371 
TEST(ExtensionL10nUtil,LocalizeManifestWithNameDescriptionFileHandlerTitle)372 TEST(ExtensionL10nUtil, LocalizeManifestWithNameDescriptionFileHandlerTitle) {
373   DictionaryValue manifest;
374   manifest.SetString(keys::kName, "__MSG_name__");
375   manifest.SetString(keys::kDescription, "__MSG_description__");
376   ListValue* handlers = new ListValue();
377   manifest.Set(keys::kFileBrowserHandlers, handlers);
378   DictionaryValue* handler = new DictionaryValue();
379   handlers->Append(handler);
380   handler->SetString(keys::kPageActionDefaultTitle,
381                      "__MSG_file_handler_title__");
382 
383   std::string error;
384   scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle());
385 
386   EXPECT_TRUE(
387       extension_l10n_util::LocalizeManifest(*messages, &manifest, &error));
388 
389   std::string result;
390   ASSERT_TRUE(manifest.GetString(keys::kName, &result));
391   EXPECT_EQ("name", result);
392 
393   ASSERT_TRUE(manifest.GetString(keys::kDescription, &result));
394   EXPECT_EQ("description", result);
395 
396   ASSERT_TRUE(handler->GetString(keys::kPageActionDefaultTitle, &result));
397   EXPECT_EQ("file handler title", result);
398 
399   EXPECT_TRUE(error.empty());
400 }
401 
402 // Try with NULL manifest.
TEST(ExtensionL10nUtil,ShouldRelocalizeManifestWithNullManifest)403 TEST(ExtensionL10nUtil, ShouldRelocalizeManifestWithNullManifest) {
404   ExtensionInfo info(NULL, "", FilePath(), Extension::LOAD);
405 
406   EXPECT_FALSE(extension_l10n_util::ShouldRelocalizeManifest(info));
407 }
408 
409 // Try with default and current locales missing.
TEST(ExtensionL10nUtil,ShouldRelocalizeManifestEmptyManifest)410 TEST(ExtensionL10nUtil, ShouldRelocalizeManifestEmptyManifest) {
411   DictionaryValue manifest;
412   ExtensionInfo info(&manifest, "", FilePath(), Extension::LOAD);
413 
414   EXPECT_FALSE(extension_l10n_util::ShouldRelocalizeManifest(info));
415 }
416 
417 // Try with missing current_locale.
TEST(ExtensionL10nUtil,ShouldRelocalizeManifestWithDefaultLocale)418 TEST(ExtensionL10nUtil, ShouldRelocalizeManifestWithDefaultLocale) {
419   DictionaryValue manifest;
420   manifest.SetString(keys::kDefaultLocale, "en_US");
421 
422   ExtensionInfo info(&manifest, "", FilePath(), Extension::LOAD);
423 
424   EXPECT_TRUE(extension_l10n_util::ShouldRelocalizeManifest(info));
425 }
426 
427 // Try with missing default_locale.
TEST(ExtensionL10nUtil,ShouldRelocalizeManifestWithCurrentLocale)428 TEST(ExtensionL10nUtil, ShouldRelocalizeManifestWithCurrentLocale) {
429   DictionaryValue manifest;
430   manifest.SetString(keys::kCurrentLocale,
431                      extension_l10n_util::CurrentLocaleOrDefault());
432 
433   ExtensionInfo info(&manifest, "", FilePath(), Extension::LOAD);
434 
435   EXPECT_FALSE(extension_l10n_util::ShouldRelocalizeManifest(info));
436 }
437 
438 // Try with all data present, but with same current_locale as system locale.
TEST(ExtensionL10nUtil,ShouldRelocalizeManifestSameCurrentLocale)439 TEST(ExtensionL10nUtil, ShouldRelocalizeManifestSameCurrentLocale) {
440   DictionaryValue manifest;
441   manifest.SetString(keys::kDefaultLocale, "en_US");
442   manifest.SetString(keys::kCurrentLocale,
443                      extension_l10n_util::CurrentLocaleOrDefault());
444 
445   ExtensionInfo info(&manifest, "", FilePath(), Extension::LOAD);
446 
447   EXPECT_FALSE(extension_l10n_util::ShouldRelocalizeManifest(info));
448 }
449 
450 // Try with all data present, but with different current_locale.
TEST(ExtensionL10nUtil,ShouldRelocalizeManifestDifferentCurrentLocale)451 TEST(ExtensionL10nUtil, ShouldRelocalizeManifestDifferentCurrentLocale) {
452   DictionaryValue manifest;
453   manifest.SetString(keys::kDefaultLocale, "en_US");
454   manifest.SetString(keys::kCurrentLocale, "sr");
455 
456   ExtensionInfo info(&manifest, "", FilePath(), Extension::LOAD);
457 
458   EXPECT_TRUE(extension_l10n_util::ShouldRelocalizeManifest(info));
459 }
460 
461 }  // namespace
462