Home | History | Annotate | Download | only in extensions
      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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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.
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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.
    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.
    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.
    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.
    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.
    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