extension_l10n_util_unittest.cc revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
1// Copyright (c) 2010 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 "app/l10n_util.h" 6#include "base/file_path.h" 7#include "base/file_util.h" 8#include "base/linked_ptr.h" 9#include "base/path_service.h" 10#include "base/scoped_ptr.h" 11#include "base/scoped_temp_dir.h" 12#include "base/values.h" 13#include "chrome/common/chrome_paths.h" 14#include "chrome/common/extensions/extension.h" 15#include "chrome/common/extensions/extension_constants.h" 16#include "chrome/common/extensions/extension_l10n_util.h" 17#include "chrome/common/extensions/extension_message_bundle.h" 18#include "testing/gtest/include/gtest/gtest.h" 19 20namespace errors = extension_manifest_errors; 21namespace keys = extension_manifest_keys; 22 23namespace { 24 25TEST(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 41TEST(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 58TEST(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 85TEST(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 106TEST(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 131TEST(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 150TEST(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 177TEST(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 217TEST(ExtensionL10nUtil, GetParentLocales) { 218 std::vector<std::string> locales; 219 const std::string top_locale("sr_Cyrl_RS"); 220 extension_l10n_util::GetParentLocales(top_locale, &locales); 221 222 ASSERT_EQ(3U, locales.size()); 223 EXPECT_EQ("sr_Cyrl_RS", locales[0]); 224 EXPECT_EQ("sr_Cyrl", locales[1]); 225 EXPECT_EQ("sr", locales[2]); 226} 227 228// Caller owns the returned object. 229ExtensionMessageBundle* CreateManifestBundle() { 230 linked_ptr<DictionaryValue> catalog(new DictionaryValue); 231 232 DictionaryValue* name_tree = new DictionaryValue(); 233 name_tree->SetString("message", "name"); 234 catalog->Set("name", name_tree); 235 236 DictionaryValue* description_tree = new DictionaryValue(); 237 description_tree->SetString("message", "description"); 238 catalog->Set("description", description_tree); 239 240 DictionaryValue* action_title_tree = new DictionaryValue(); 241 action_title_tree->SetString("message", "action title"); 242 catalog->Set("title", action_title_tree); 243 244 DictionaryValue* omnibox_keyword_tree = new DictionaryValue(); 245 omnibox_keyword_tree->SetString("message", "omnibox keyword"); 246 catalog->Set("omnibox_keyword", omnibox_keyword_tree); 247 248 std::vector<linked_ptr<DictionaryValue> > catalogs; 249 catalogs.push_back(catalog); 250 251 std::string error; 252 ExtensionMessageBundle* bundle = 253 ExtensionMessageBundle::Create(catalogs, &error); 254 EXPECT_TRUE(bundle); 255 EXPECT_TRUE(error.empty()); 256 257 return bundle; 258} 259 260TEST(ExtensionL10nUtil, LocalizeEmptyManifest) { 261 DictionaryValue manifest; 262 std::string error; 263 scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle()); 264 265 EXPECT_FALSE( 266 extension_l10n_util::LocalizeManifest(*messages, &manifest, &error)); 267 EXPECT_EQ(errors::kInvalidName, error); 268} 269 270TEST(ExtensionL10nUtil, LocalizeManifestWithoutNameMsgAndEmptyDescription) { 271 DictionaryValue manifest; 272 manifest.SetString(keys::kName, "no __MSG"); 273 std::string error; 274 scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle()); 275 276 EXPECT_TRUE( 277 extension_l10n_util::LocalizeManifest(*messages, &manifest, &error)); 278 279 std::string result; 280 ASSERT_TRUE(manifest.GetString(keys::kName, &result)); 281 EXPECT_EQ("no __MSG", result); 282 283 EXPECT_FALSE(manifest.HasKey(keys::kDescription)); 284 285 EXPECT_TRUE(error.empty()); 286} 287 288TEST(ExtensionL10nUtil, LocalizeManifestWithNameMsgAndEmptyDescription) { 289 DictionaryValue manifest; 290 manifest.SetString(keys::kName, "__MSG_name__"); 291 std::string error; 292 scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle()); 293 294 EXPECT_TRUE( 295 extension_l10n_util::LocalizeManifest(*messages, &manifest, &error)); 296 297 std::string result; 298 ASSERT_TRUE(manifest.GetString(keys::kName, &result)); 299 EXPECT_EQ("name", result); 300 301 EXPECT_FALSE(manifest.HasKey(keys::kDescription)); 302 303 EXPECT_TRUE(error.empty()); 304} 305 306TEST(ExtensionL10nUtil, LocalizeManifestWithBadNameMsg) { 307 DictionaryValue manifest; 308 manifest.SetString(keys::kName, "__MSG_name_is_bad__"); 309 manifest.SetString(keys::kDescription, "__MSG_description__"); 310 std::string error; 311 scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle()); 312 313 EXPECT_FALSE( 314 extension_l10n_util::LocalizeManifest(*messages, &manifest, &error)); 315 316 std::string result; 317 ASSERT_TRUE(manifest.GetString(keys::kName, &result)); 318 EXPECT_EQ("__MSG_name_is_bad__", result); 319 320 ASSERT_TRUE(manifest.GetString(keys::kDescription, &result)); 321 EXPECT_EQ("__MSG_description__", result); 322 323 EXPECT_EQ("Variable __MSG_name_is_bad__ used but not defined.", error); 324} 325 326TEST(ExtensionL10nUtil, LocalizeManifestWithNameDescriptionDefaultTitleMsgs) { 327 DictionaryValue manifest; 328 manifest.SetString(keys::kName, "__MSG_name__"); 329 manifest.SetString(keys::kDescription, "__MSG_description__"); 330 std::string action_title(keys::kBrowserAction); 331 action_title.append("."); 332 action_title.append(keys::kPageActionDefaultTitle); 333 manifest.SetString(action_title, "__MSG_title__"); 334 335 std::string error; 336 scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle()); 337 338 EXPECT_TRUE( 339 extension_l10n_util::LocalizeManifest(*messages, &manifest, &error)); 340 341 std::string result; 342 ASSERT_TRUE(manifest.GetString(keys::kName, &result)); 343 EXPECT_EQ("name", result); 344 345 ASSERT_TRUE(manifest.GetString(keys::kDescription, &result)); 346 EXPECT_EQ("description", result); 347 348 ASSERT_TRUE(manifest.GetString(action_title, &result)); 349 EXPECT_EQ("action title", result); 350 351 EXPECT_TRUE(error.empty()); 352} 353 354TEST(ExtensionL10nUtil, LocalizeManifestWithNameDescriptionOmniboxMsgs) { 355 DictionaryValue manifest; 356 manifest.SetString(keys::kName, "__MSG_name__"); 357 manifest.SetString(keys::kDescription, "__MSG_description__"); 358 manifest.SetString(keys::kOmniboxKeyword, "__MSG_omnibox_keyword__"); 359 360 std::string error; 361 scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle()); 362 363 EXPECT_TRUE( 364 extension_l10n_util::LocalizeManifest(*messages, &manifest, &error)); 365 366 std::string result; 367 ASSERT_TRUE(manifest.GetString(keys::kName, &result)); 368 EXPECT_EQ("name", result); 369 370 ASSERT_TRUE(manifest.GetString(keys::kDescription, &result)); 371 EXPECT_EQ("description", result); 372 373 ASSERT_TRUE(manifest.GetString(keys::kOmniboxKeyword, &result)); 374 EXPECT_EQ("omnibox keyword", result); 375 376 EXPECT_TRUE(error.empty()); 377} 378 379// Try with NULL manifest. 380TEST(ExtensionL10nUtil, ShouldRelocalizeManifestWithNullManifest) { 381 ExtensionInfo info(NULL, "", FilePath(), Extension::LOAD); 382 383 EXPECT_FALSE(extension_l10n_util::ShouldRelocalizeManifest(info)); 384} 385 386// Try with default and current locales missing. 387TEST(ExtensionL10nUtil, ShouldRelocalizeManifestEmptyManifest) { 388 DictionaryValue manifest; 389 ExtensionInfo info(&manifest, "", FilePath(), Extension::LOAD); 390 391 EXPECT_FALSE(extension_l10n_util::ShouldRelocalizeManifest(info)); 392} 393 394// Try with missing current_locale. 395TEST(ExtensionL10nUtil, ShouldRelocalizeManifestWithDefaultLocale) { 396 DictionaryValue manifest; 397 manifest.SetString(keys::kDefaultLocale, "en_US"); 398 399 ExtensionInfo info(&manifest, "", FilePath(), Extension::LOAD); 400 401 EXPECT_TRUE(extension_l10n_util::ShouldRelocalizeManifest(info)); 402} 403 404// Try with missing default_locale. 405TEST(ExtensionL10nUtil, ShouldRelocalizeManifestWithCurrentLocale) { 406 DictionaryValue manifest; 407 manifest.SetString(keys::kCurrentLocale, 408 extension_l10n_util::CurrentLocaleOrDefault()); 409 410 ExtensionInfo info(&manifest, "", FilePath(), Extension::LOAD); 411 412 EXPECT_FALSE(extension_l10n_util::ShouldRelocalizeManifest(info)); 413} 414 415// Try with all data present, but with same current_locale as system locale. 416TEST(ExtensionL10nUtil, ShouldRelocalizeManifestSameCurrentLocale) { 417 DictionaryValue manifest; 418 manifest.SetString(keys::kDefaultLocale, "en_US"); 419 manifest.SetString(keys::kCurrentLocale, 420 extension_l10n_util::CurrentLocaleOrDefault()); 421 422 ExtensionInfo info(&manifest, "", FilePath(), Extension::LOAD); 423 424 EXPECT_FALSE(extension_l10n_util::ShouldRelocalizeManifest(info)); 425} 426 427// Try with all data present, but with different current_locale. 428TEST(ExtensionL10nUtil, ShouldRelocalizeManifestDifferentCurrentLocale) { 429 DictionaryValue manifest; 430 manifest.SetString(keys::kDefaultLocale, "en_US"); 431 manifest.SetString(keys::kCurrentLocale, "sr"); 432 433 ExtensionInfo info(&manifest, "", FilePath(), Extension::LOAD); 434 435 EXPECT_TRUE(extension_l10n_util::ShouldRelocalizeManifest(info)); 436} 437 438} // namespace 439