input_method_util_unittest.cc revision 3240926e260ce088908e02ac07a6cf7b0c0cbf44
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 "chrome/browser/chromeos/input_method/input_method_util.h" 6 7#include <string> 8 9#include "base/bind.h" 10#include "base/memory/scoped_ptr.h" 11#include "base/strings/utf_string_conversions.h" 12#include "chromeos/ime/fake_input_method_delegate.h" 13#include "chromeos/ime/input_method_manager.h" 14#include "chromeos/ime/input_method_whitelist.h" 15#include "grit/generated_resources.h" 16#include "testing/gtest/include/gtest/gtest.h" 17#include "ui/base/l10n/l10n_util.h" 18 19namespace chromeos { 20 21extern const char* kExtensionImePrefix; 22 23namespace input_method { 24 25namespace { 26 27const char pinyin_ime_id[] = 28 "_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabzh-t-i0-pinyin"; 29const char zhuyin_ime_id[] = 30 "_comp_ime_goedamlknlnjaengojinmfgpmdjmkooozh-hant-t-i0-und"; 31 32class TestableInputMethodUtil : public InputMethodUtil { 33 public: 34 explicit TestableInputMethodUtil(InputMethodDelegate* delegate, 35 scoped_ptr<InputMethodDescriptors> methods) 36 : InputMethodUtil(delegate, methods.Pass()) { 37 } 38 // Change access rights. 39 using InputMethodUtil::GetInputMethodIdsFromLanguageCodeInternal; 40 using InputMethodUtil::GetKeyboardLayoutName; 41 using InputMethodUtil::ReloadInternalMaps; 42 using InputMethodUtil::supported_input_methods_; 43}; 44 45} // namespace 46 47class InputMethodUtilTest : public testing::Test { 48 public: 49 InputMethodUtilTest() 50 : util_(&delegate_, whitelist_.GetSupportedInputMethods()) { 51 delegate_.set_get_localized_string_callback( 52 base::Bind(&l10n_util::GetStringUTF16)); 53 delegate_.set_get_display_language_name_callback( 54 base::Bind(&InputMethodUtilTest::GetDisplayLanguageName)); 55 } 56 57 virtual void SetUp() OVERRIDE { 58 InputMethodDescriptors input_methods; 59 60 std::vector<std::string> layouts; 61 std::vector<std::string> languages; 62 layouts.push_back("us"); 63 languages.push_back("zh-CN"); 64 65 InputMethodDescriptor pinyin_ime(pinyin_ime_id, 66 "Pinyin input for testing", 67 layouts, 68 languages, 69 GURL("")); 70 input_methods.push_back(pinyin_ime); 71 72 languages.clear(); 73 languages.push_back("zh-TW"); 74 InputMethodDescriptor zhuyin_ime(zhuyin_ime_id, 75 "Zhuyin input for testing", 76 layouts, 77 languages, 78 GURL("")); 79 input_methods.push_back(zhuyin_ime); 80 81 util_.SetComponentExtensions(input_methods); 82 } 83 84 InputMethodDescriptor GetDesc(const std::string& id, 85 const std::string& raw_layout, 86 const std::string& language_code) { 87 std::vector<std::string> layouts; 88 layouts.push_back(raw_layout); 89 std::vector<std::string> languages; 90 languages.push_back(language_code); 91 return InputMethodDescriptor(id, 92 "", 93 layouts, 94 languages, 95 GURL()); // options page url 96 } 97 98 static string16 GetDisplayLanguageName(const std::string& language_code) { 99 return l10n_util::GetDisplayNameForLocale(language_code, "en", true); 100 } 101 102 FakeInputMethodDelegate delegate_; 103 InputMethodWhitelist whitelist_; 104 TestableInputMethodUtil util_; 105}; 106 107TEST_F(InputMethodUtilTest, GetInputMethodShortNameTest) { 108 // Test normal cases. Two-letter language code should be returned. 109 { 110 InputMethodDescriptor desc = GetDesc("m17n:fa:isiri", // input method id 111 "us", // keyboard layout name 112 "fa"); // language name 113 EXPECT_EQ(ASCIIToUTF16("FA"), util_.GetInputMethodShortName(desc)); 114 } 115 { 116 InputMethodDescriptor desc = GetDesc("mozc-hangul", "us", "ko"); 117 EXPECT_EQ(UTF8ToUTF16("\xed\x95\x9c"), 118 util_.GetInputMethodShortName(desc)); 119 } 120 { 121 InputMethodDescriptor desc = GetDesc("invalid-id", "us", "xx"); 122 // Upper-case string of the unknown language code, "xx", should be returned. 123 EXPECT_EQ(ASCIIToUTF16("XX"), util_.GetInputMethodShortName(desc)); 124 } 125 126 // Test special cases. 127 { 128 InputMethodDescriptor desc = GetDesc("xkb:us:dvorak:eng", "us", "en-US"); 129 EXPECT_EQ(ASCIIToUTF16("DV"), util_.GetInputMethodShortName(desc)); 130 } 131 { 132 InputMethodDescriptor desc = GetDesc("xkb:us:colemak:eng", "us", "en-US"); 133 EXPECT_EQ(ASCIIToUTF16("CO"), util_.GetInputMethodShortName(desc)); 134 } 135 { 136 InputMethodDescriptor desc = 137 GetDesc("xkb:us:altgr-intl:eng", "us", "en-US"); 138 EXPECT_EQ(ASCIIToUTF16("EXTD"), util_.GetInputMethodShortName(desc)); 139 } 140 { 141 InputMethodDescriptor desc = GetDesc("xkb:us:intl:eng", "us", "en-US"); 142 EXPECT_EQ(ASCIIToUTF16("INTL"), util_.GetInputMethodShortName(desc)); 143 } 144 { 145 InputMethodDescriptor desc = GetDesc("xkb:de:neo:ger", "de(neo)", "de"); 146 EXPECT_EQ(ASCIIToUTF16("NEO"), util_.GetInputMethodShortName(desc)); 147 } 148 { 149 InputMethodDescriptor desc = GetDesc("xkb:es:cat:cat", "es(cat)", "ca"); 150 EXPECT_EQ(ASCIIToUTF16("CAS"), util_.GetInputMethodShortName(desc)); 151 } 152 { 153 InputMethodDescriptor desc = GetDesc(pinyin_ime_id, "us", "zh-CN"); 154 EXPECT_EQ(UTF8ToUTF16("\xe6\x8b\xbc"), 155 util_.GetInputMethodShortName(desc)); 156 } 157 { 158 InputMethodDescriptor desc = GetDesc(zhuyin_ime_id, "us", "zh-TW"); 159 EXPECT_EQ(UTF8ToUTF16("\xe9\x85\xb7"), 160 util_.GetInputMethodShortName(desc)); 161 } 162 { 163 InputMethodDescriptor desc = GetDesc("m17n:zh:cangjie", "us", "zh-TW"); 164 EXPECT_EQ(UTF8ToUTF16("\xe5\x80\x89"), 165 util_.GetInputMethodShortName(desc)); 166 } 167 { 168 InputMethodDescriptor desc = GetDesc("m17n:zh:quick", "us", "zh-TW"); 169 EXPECT_EQ(UTF8ToUTF16("\xe9\x80\x9f"), 170 util_.GetInputMethodShortName(desc)); 171 } 172} 173 174TEST_F(InputMethodUtilTest, GetInputMethodMediumNameTest) { 175 { 176 // input methods with medium name equal to short name 177 const char * input_method_id[] = { 178 "xkb:us:altgr-intl:eng", 179 "xkb:us:dvorak:eng", 180 "xkb:us:intl:eng", 181 "xkb:us:colemak:eng", 182 "english-m", 183 "xkb:de:neo:ger", 184 "xkb:es:cat:cat", 185 "xkb:gb:dvorak:eng", 186 }; 187 const int len = ARRAYSIZE_UNSAFE(input_method_id); 188 for (int i=0; i<len; ++i) { 189 InputMethodDescriptor desc = GetDesc(input_method_id[i], "", ""); 190 string16 medium_name = util_.GetInputMethodMediumName(desc); 191 string16 short_name = util_.GetInputMethodShortName(desc); 192 EXPECT_EQ(medium_name,short_name); 193 } 194 } 195 { 196 // input methods with medium name not equal to short name 197 const char * input_method_id[] = { 198 "m17n:zh:cangjie", 199 "m17n:zh:quick", 200 pinyin_ime_id, 201 zhuyin_ime_id, 202 "mozc-hangul", 203 pinyin_ime_id, 204 pinyin_ime_id, 205 }; 206 const int len = ARRAYSIZE_UNSAFE(input_method_id); 207 for (int i=0; i<len; ++i) { 208 InputMethodDescriptor desc = GetDesc(input_method_id[i], "", ""); 209 string16 medium_name = util_.GetInputMethodMediumName(desc); 210 string16 short_name = util_.GetInputMethodShortName(desc); 211 EXPECT_NE(medium_name,short_name); 212 } 213 } 214} 215 216TEST_F(InputMethodUtilTest, GetInputMethodLongNameTest) { 217 // For most languages input method or keyboard layout name is returned. 218 // See below for exceptions. 219 { 220 InputMethodDescriptor desc = GetDesc("m17n:fa:isiri", "us", "fa"); 221 EXPECT_EQ(ASCIIToUTF16("Persian input method (ISIRI 2901 layout)"), 222 util_.GetInputMethodLongName(desc)); 223 } 224 { 225 InputMethodDescriptor desc = GetDesc("mozc-hangul", "us", "ko"); 226 EXPECT_EQ(ASCIIToUTF16("Korean input method"), 227 util_.GetInputMethodLongName(desc)); 228 } 229 { 230 InputMethodDescriptor desc = GetDesc("m17n:vi:tcvn", "us", "vi"); 231 EXPECT_EQ(ASCIIToUTF16("Vietnamese input method (TCVN6064)"), 232 util_.GetInputMethodLongName(desc)); 233 } 234 { 235 InputMethodDescriptor desc = GetDesc("xkb:jp::jpn", "jp", "ja"); 236 EXPECT_EQ(ASCIIToUTF16("Japanese keyboard"), 237 util_.GetInputMethodLongName(desc)); 238 } 239 { 240 InputMethodDescriptor desc = 241 GetDesc("xkb:us:dvorak:eng", "us(dvorak)", "en-US"); 242 EXPECT_EQ(ASCIIToUTF16("US Dvorak keyboard"), 243 util_.GetInputMethodLongName(desc)); 244 } 245 { 246 InputMethodDescriptor desc = 247 GetDesc("xkb:gb:dvorak:eng", "gb(dvorak)", "en-US"); 248 EXPECT_EQ(ASCIIToUTF16("UK Dvorak keyboard"), 249 util_.GetInputMethodLongName(desc)); 250 } 251 252 // For Arabic, Dutch, French, German and Hindi, 253 // "language - keyboard layout" pair is returned. 254 { 255 InputMethodDescriptor desc = GetDesc("m17n:ar:kbd", "us", "ar"); 256 EXPECT_EQ(ASCIIToUTF16("Arabic - Standard input method"), 257 util_.GetInputMethodLongName(desc)); 258 } 259 { 260 InputMethodDescriptor desc = GetDesc("xkb:be::nld", "be", "nl"); 261 EXPECT_EQ(ASCIIToUTF16("Dutch - Belgian keyboard"), 262 util_.GetInputMethodLongName(desc)); 263 } 264 { 265 InputMethodDescriptor desc = GetDesc("xkb:fr::fra", "fr", "fr"); 266 EXPECT_EQ(ASCIIToUTF16("French - French keyboard"), 267 util_.GetInputMethodLongName(desc)); 268 } 269 { 270 InputMethodDescriptor desc = GetDesc("xkb:be::fra", "be", "fr"); 271 EXPECT_EQ(ASCIIToUTF16("French - Belgian keyboard"), 272 util_.GetInputMethodLongName(desc)); 273 } 274 { 275 InputMethodDescriptor desc = GetDesc("xkb:de::ger", "de", "de"); 276 EXPECT_EQ(ASCIIToUTF16("German - German keyboard"), 277 util_.GetInputMethodLongName(desc)); 278 } 279 { 280 InputMethodDescriptor desc = GetDesc("xkb:be::ger", "be", "de"); 281 EXPECT_EQ(ASCIIToUTF16("German - Belgian keyboard"), 282 util_.GetInputMethodLongName(desc)); 283 } 284 { 285 InputMethodDescriptor desc = GetDesc("m17n:hi:itrans", "us", "hi"); 286 EXPECT_EQ(ASCIIToUTF16("Hindi - Standard input method"), 287 util_.GetInputMethodLongName(desc)); 288 } 289 290 { 291 InputMethodDescriptor desc = GetDesc("invalid-id", "us", "xx"); 292 // You can safely ignore the "Resouce ID is not found for: invalid-id" 293 // error. 294 EXPECT_EQ(ASCIIToUTF16("invalid-id"), 295 util_.GetInputMethodLongName(desc)); 296 } 297} 298 299TEST_F(InputMethodUtilTest, TestIsValidInputMethodId) { 300 EXPECT_TRUE(util_.IsValidInputMethodId("xkb:us:colemak:eng")); 301 EXPECT_TRUE(util_.IsValidInputMethodId(pinyin_ime_id)); 302 EXPECT_FALSE(util_.IsValidInputMethodId("unsupported-input-method")); 303} 304 305TEST_F(InputMethodUtilTest, TestIsKeyboardLayout) { 306 EXPECT_TRUE(InputMethodUtil::IsKeyboardLayout("xkb:us::eng")); 307 EXPECT_FALSE(InputMethodUtil::IsKeyboardLayout(pinyin_ime_id)); 308} 309 310TEST_F(InputMethodUtilTest, TestGetKeyboardLayoutName) { 311 // Unsupported case. 312 EXPECT_EQ("", util_.GetKeyboardLayoutName("UNSUPPORTED_ID")); 313 314 // Supported cases (samples). 315 EXPECT_EQ("us", util_.GetKeyboardLayoutName(pinyin_ime_id)); 316 EXPECT_EQ("es", util_.GetKeyboardLayoutName("xkb:es::spa")); 317 EXPECT_EQ("es(cat)", util_.GetKeyboardLayoutName("xkb:es:cat:cat")); 318 EXPECT_EQ("gb(extd)", util_.GetKeyboardLayoutName("xkb:gb:extd:eng")); 319 EXPECT_EQ("us", util_.GetKeyboardLayoutName("xkb:us::eng")); 320 EXPECT_EQ("us(dvorak)", util_.GetKeyboardLayoutName("xkb:us:dvorak:eng")); 321 EXPECT_EQ("us(colemak)", util_.GetKeyboardLayoutName("xkb:us:colemak:eng")); 322 EXPECT_EQ("de(neo)", util_.GetKeyboardLayoutName("xkb:de:neo:ger")); 323} 324 325TEST_F(InputMethodUtilTest, TestGetLanguageCodeFromInputMethodId) { 326 // Make sure that the -CN is added properly. 327 EXPECT_EQ("zh-CN", util_.GetLanguageCodeFromInputMethodId(pinyin_ime_id)); 328} 329 330TEST_F(InputMethodUtilTest, TestGetInputMethodDisplayNameFromId) { 331 EXPECT_EQ("US keyboard", 332 util_.GetInputMethodDisplayNameFromId("xkb:us::eng")); 333 EXPECT_EQ("", util_.GetInputMethodDisplayNameFromId("nonexistent")); 334} 335 336TEST_F(InputMethodUtilTest, TestGetInputMethodDescriptorFromId) { 337 EXPECT_EQ(NULL, util_.GetInputMethodDescriptorFromId("non_existent")); 338 339 const InputMethodDescriptor* descriptor = 340 util_.GetInputMethodDescriptorFromId(pinyin_ime_id); 341 ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. 342 EXPECT_EQ(pinyin_ime_id, descriptor->id()); 343 EXPECT_EQ("us", descriptor->GetPreferredKeyboardLayout()); 344 // This used to be "zh" but now we have "zh-CN" in input_methods.h, 345 // hence this should be zh-CN now. 346 ASSERT_TRUE(!descriptor->language_codes().empty()); 347 EXPECT_EQ("zh-CN", descriptor->language_codes().at(0)); 348} 349 350TEST_F(InputMethodUtilTest, TestGetInputMethodIdsForLanguageCode) { 351 std::multimap<std::string, std::string> language_code_to_ids_map; 352 language_code_to_ids_map.insert(std::make_pair("ja", pinyin_ime_id)); 353 language_code_to_ids_map.insert(std::make_pair("ja", pinyin_ime_id)); 354 language_code_to_ids_map.insert(std::make_pair("ja", "xkb:jp:jpn")); 355 language_code_to_ids_map.insert(std::make_pair("fr", "xkb:fr:fra")); 356 357 std::vector<std::string> result; 358 EXPECT_TRUE(util_.GetInputMethodIdsFromLanguageCodeInternal( 359 language_code_to_ids_map, "ja", kAllInputMethods, &result)); 360 EXPECT_EQ(3U, result.size()); 361 EXPECT_TRUE(util_.GetInputMethodIdsFromLanguageCodeInternal( 362 language_code_to_ids_map, "ja", kKeyboardLayoutsOnly, &result)); 363 ASSERT_EQ(1U, result.size()); 364 EXPECT_EQ("xkb:jp:jpn", result[0]); 365 366 EXPECT_TRUE(util_.GetInputMethodIdsFromLanguageCodeInternal( 367 language_code_to_ids_map, "fr", kAllInputMethods, &result)); 368 ASSERT_EQ(1U, result.size()); 369 EXPECT_EQ("xkb:fr:fra", result[0]); 370 EXPECT_TRUE(util_.GetInputMethodIdsFromLanguageCodeInternal( 371 language_code_to_ids_map, "fr", kKeyboardLayoutsOnly, &result)); 372 ASSERT_EQ(1U, result.size()); 373 EXPECT_EQ("xkb:fr:fra", result[0]); 374 375 EXPECT_FALSE(util_.GetInputMethodIdsFromLanguageCodeInternal( 376 language_code_to_ids_map, "invalid_lang", kAllInputMethods, &result)); 377 EXPECT_FALSE(util_.GetInputMethodIdsFromLanguageCodeInternal( 378 language_code_to_ids_map, "invalid_lang", kKeyboardLayoutsOnly, &result)); 379} 380 381// US keyboard + English US UI = US keyboard only. 382TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_Us_And_EnUs) { 383 const InputMethodDescriptor* descriptor = 384 util_.GetInputMethodDescriptorFromId("xkb:us::eng"); // US keyboard. 385 ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. 386 std::vector<std::string> input_method_ids; 387 util_.GetFirstLoginInputMethodIds("en-US", *descriptor, &input_method_ids); 388 ASSERT_EQ(1U, input_method_ids.size()); 389 EXPECT_EQ("xkb:us::eng", input_method_ids[0]); 390} 391 392// US keyboard + Chinese UI = US keyboard + Pinyin IME. 393TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_Us_And_Zh) { 394 const InputMethodDescriptor* descriptor = 395 util_.GetInputMethodDescriptorFromId("xkb:us::eng"); // US keyboard. 396 ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. 397 std::vector<std::string> input_method_ids; 398 util_.GetFirstLoginInputMethodIds("zh-CN", *descriptor, &input_method_ids); 399 ASSERT_EQ(2U, input_method_ids.size()); 400 EXPECT_EQ("xkb:us::eng", input_method_ids[0]); 401 EXPECT_EQ(pinyin_ime_id, input_method_ids[1]); // Pinyin for US keybaord. 402} 403 404// US keyboard + Russian UI = US keyboard + Russsian keyboard 405TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_Us_And_Ru) { 406 const InputMethodDescriptor* descriptor = 407 util_.GetInputMethodDescriptorFromId("xkb:us::eng"); // US keyboard. 408 ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. 409 std::vector<std::string> input_method_ids; 410 util_.GetFirstLoginInputMethodIds("ru", *descriptor, &input_method_ids); 411 ASSERT_EQ(2U, input_method_ids.size()); 412 EXPECT_EQ("xkb:us::eng", input_method_ids[0]); 413 EXPECT_EQ("xkb:ru::rus", input_method_ids[1]); // Russian keyboard. 414} 415 416// US keyboard + Thai = US keyboard + kesmanee. 417TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_Us_And_Th) { 418 const InputMethodDescriptor* descriptor = 419 util_.GetInputMethodDescriptorFromId("xkb:us::eng"); // US keyboard. 420 ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. 421 std::vector<std::string> input_method_ids; 422 util_.GetFirstLoginInputMethodIds("th", *descriptor, &input_method_ids); 423 ASSERT_EQ(2U, input_method_ids.size()); 424 EXPECT_EQ("xkb:us::eng", input_method_ids[0]); 425 EXPECT_EQ("_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_th", 426 input_method_ids[1]); // Kesmanee. 427} 428 429// US keyboard + Vietnamese = US keyboard + TCVN6064. 430TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_Us_And_Vi) { 431 const InputMethodDescriptor* descriptor = 432 util_.GetInputMethodDescriptorFromId("xkb:us::eng"); // US keyboard. 433 ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. 434 std::vector<std::string> input_method_ids; 435 util_.GetFirstLoginInputMethodIds("vi", *descriptor, &input_method_ids); 436 ASSERT_EQ(2U, input_method_ids.size()); 437 EXPECT_EQ("xkb:us::eng", input_method_ids[0]); 438 EXPECT_EQ("_comp_ime_jhffeifommiaekmbkkjlpmilogcfdohpvkd_vi_tcvn", 439 input_method_ids[1]); // TCVN6064. 440} 441 442TEST_F(InputMethodUtilTest, TestGetLanguageCodesFromInputMethodIds) { 443 std::vector<std::string> input_method_ids; 444 input_method_ids.push_back("xkb:us::eng"); // English US. 445 input_method_ids.push_back("xkb:us:dvorak:eng"); // English US Dvorak. 446 input_method_ids.push_back(pinyin_ime_id); // Pinyin 447 input_method_ids.push_back("xkb:fr::fra"); // French France. 448 std::vector<std::string> language_codes; 449 util_.GetLanguageCodesFromInputMethodIds(input_method_ids, &language_codes); 450 ASSERT_EQ(3U, language_codes.size()); 451 EXPECT_EQ("en-US", language_codes[0]); 452 EXPECT_EQ("zh-CN", language_codes[1]); 453 EXPECT_EQ("fr", language_codes[2]); 454} 455 456// Test all supported descriptors to detect a typo in ibus_input_methods.txt. 457TEST_F(InputMethodUtilTest, TestIBusInputMethodText) { 458 for (size_t i = 0; i < util_.supported_input_methods_->size(); ++i) { 459 const std::string language_code = 460 util_.supported_input_methods_->at(i).language_codes().at(0); 461 const string16 display_name = 462 l10n_util::GetDisplayNameForLocale(language_code, "en", false); 463 // Only two formats, like "fr" (lower case) and "en-US" (lower-upper), are 464 // allowed. See the text file for details. 465 EXPECT_TRUE(language_code.length() == 2 || 466 (language_code.length() == 5 && language_code[2] == '-')) 467 << "Invalid language code " << language_code; 468 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax(language_code)) 469 << "Invalid language code " << language_code; 470 EXPECT_FALSE(display_name.empty()) 471 << "Invalid language code " << language_code; 472 // On error, GetDisplayNameForLocale() returns the |language_code| as-is. 473 EXPECT_NE(language_code, UTF16ToUTF8(display_name)) 474 << "Invalid language code " << language_code; 475 } 476} 477 478} // namespace input_method 479} // namespace chromeos 480