// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/input_method/input_method_util.h" #include #include "base/bind.h" #include "base/memory/scoped_ptr.h" #include "base/utf_string_conversions.h" #include "chromeos/ime/fake_input_method_delegate.h" #include "chromeos/ime/input_method_manager.h" #include "chromeos/ime/input_method_whitelist.h" #include "grit/generated_resources.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/l10n/l10n_util.h" namespace chromeos { extern const char* kExtensionImePrefix; namespace input_method { namespace { class TestableInputMethodUtil : public InputMethodUtil { public: explicit TestableInputMethodUtil(InputMethodDelegate* delegate, scoped_ptr methods) : InputMethodUtil(delegate, methods.Pass()) { } // Change access rights. using InputMethodUtil::GetInputMethodIdsFromLanguageCodeInternal; using InputMethodUtil::GetKeyboardLayoutName; using InputMethodUtil::ReloadInternalMaps; using InputMethodUtil::supported_input_methods_; }; } // namespace class InputMethodUtilTest : public testing::Test { public: InputMethodUtilTest() : util_(&delegate_, whitelist_.GetSupportedInputMethods()) { delegate_.set_get_localized_string_callback( base::Bind(&l10n_util::GetStringUTF16)); delegate_.set_get_display_language_name_callback( base::Bind(&InputMethodUtilTest::GetDisplayLanguageName)); } InputMethodDescriptor GetDesc(const std::string& id, const std::string& raw_layout, const std::string& language_code) { std::vector layouts; layouts.push_back(raw_layout); return InputMethodDescriptor(id, "", layouts, language_code, GURL()); // options page url } static string16 GetDisplayLanguageName(const std::string& language_code) { return l10n_util::GetDisplayNameForLocale(language_code, "en", true); } FakeInputMethodDelegate delegate_; InputMethodWhitelist whitelist_; TestableInputMethodUtil util_; }; TEST_F(InputMethodUtilTest, GetInputMethodShortNameTest) { // Test normal cases. Two-letter language code should be returned. { InputMethodDescriptor desc = GetDesc("m17n:fa:isiri", // input method id "us", // keyboard layout name "fa"); // language name EXPECT_EQ(ASCIIToUTF16("FA"), util_.GetInputMethodShortName(desc)); } { InputMethodDescriptor desc = GetDesc("mozc-hangul", "us", "ko"); EXPECT_EQ(UTF8ToUTF16("\xed\x95\x9c"), util_.GetInputMethodShortName(desc)); } { InputMethodDescriptor desc = GetDesc("invalid-id", "us", "xx"); // Upper-case string of the unknown language code, "xx", should be returned. EXPECT_EQ(ASCIIToUTF16("XX"), util_.GetInputMethodShortName(desc)); } // Test special cases. { InputMethodDescriptor desc = GetDesc("xkb:us:dvorak:eng", "us", "en-US"); EXPECT_EQ(ASCIIToUTF16("DV"), util_.GetInputMethodShortName(desc)); } { InputMethodDescriptor desc = GetDesc("xkb:us:colemak:eng", "us", "en-US"); EXPECT_EQ(ASCIIToUTF16("CO"), util_.GetInputMethodShortName(desc)); } { InputMethodDescriptor desc = GetDesc("xkb:us:altgr-intl:eng", "us", "en-US"); EXPECT_EQ(ASCIIToUTF16("EXTD"), util_.GetInputMethodShortName(desc)); } { InputMethodDescriptor desc = GetDesc("xkb:us:intl:eng", "us", "en-US"); EXPECT_EQ(ASCIIToUTF16("INTL"), util_.GetInputMethodShortName(desc)); } { InputMethodDescriptor desc = GetDesc("xkb:de:neo:ger", "de(neo)", "de"); EXPECT_EQ(ASCIIToUTF16("NEO"), util_.GetInputMethodShortName(desc)); } { InputMethodDescriptor desc = GetDesc("xkb:es:cat:cat", "es(cat)", "ca"); EXPECT_EQ(ASCIIToUTF16("CAS"), util_.GetInputMethodShortName(desc)); } { InputMethodDescriptor desc = GetDesc("pinyin", "us", "zh-CN"); EXPECT_EQ(UTF8ToUTF16("\xe6\x8b\xbc"), util_.GetInputMethodShortName(desc)); } { InputMethodDescriptor desc = GetDesc("pinyin-dv", "us(dvorak)", "zh-CN"); EXPECT_EQ(UTF8ToUTF16("\xe6\x8b\xbc"), util_.GetInputMethodShortName(desc)); } { InputMethodDescriptor desc = GetDesc("mozc-chewing", "us", "zh-TW"); EXPECT_EQ(UTF8ToUTF16("\xe9\x85\xb7"), util_.GetInputMethodShortName(desc)); } { InputMethodDescriptor desc = GetDesc("m17n:zh:cangjie", "us", "zh-TW"); EXPECT_EQ(UTF8ToUTF16("\xe5\x80\x89"), util_.GetInputMethodShortName(desc)); } { InputMethodDescriptor desc = GetDesc("m17n:zh:quick", "us", "zh-TW"); EXPECT_EQ(UTF8ToUTF16("\xe9\x80\x9f"), util_.GetInputMethodShortName(desc)); } } TEST_F(InputMethodUtilTest, GetInputMethodMediumNameTest) { { // input methods with medium name equal to short name const char * input_method_id[] = { "xkb:us:altgr-intl:eng", "xkb:us:dvorak:eng", "xkb:us:intl:eng", "xkb:us:colemak:eng", "english-m", "xkb:de:neo:ger", "xkb:es:cat:cat", "xkb:gb:dvorak:eng", }; const int len = ARRAYSIZE_UNSAFE(input_method_id); for (int i=0; iid()); EXPECT_EQ("us", descriptor->GetPreferredKeyboardLayout()); // This used to be "zh" but now we have "zh-CN" in input_methods.h, // hence this should be zh-CN now. EXPECT_EQ("zh-CN", descriptor->language_code()); } TEST_F(InputMethodUtilTest, TestGetInputMethodIdsForLanguageCode) { std::multimap language_code_to_ids_map; language_code_to_ids_map.insert(std::make_pair("ja", "pinyin")); language_code_to_ids_map.insert(std::make_pair("ja", "pinyin")); language_code_to_ids_map.insert(std::make_pair("ja", "xkb:jp:jpn")); language_code_to_ids_map.insert(std::make_pair("fr", "xkb:fr:fra")); std::vector result; EXPECT_TRUE(util_.GetInputMethodIdsFromLanguageCodeInternal( language_code_to_ids_map, "ja", kAllInputMethods, &result)); EXPECT_EQ(3U, result.size()); EXPECT_TRUE(util_.GetInputMethodIdsFromLanguageCodeInternal( language_code_to_ids_map, "ja", kKeyboardLayoutsOnly, &result)); ASSERT_EQ(1U, result.size()); EXPECT_EQ("xkb:jp:jpn", result[0]); EXPECT_TRUE(util_.GetInputMethodIdsFromLanguageCodeInternal( language_code_to_ids_map, "fr", kAllInputMethods, &result)); ASSERT_EQ(1U, result.size()); EXPECT_EQ("xkb:fr:fra", result[0]); EXPECT_TRUE(util_.GetInputMethodIdsFromLanguageCodeInternal( language_code_to_ids_map, "fr", kKeyboardLayoutsOnly, &result)); ASSERT_EQ(1U, result.size()); EXPECT_EQ("xkb:fr:fra", result[0]); EXPECT_FALSE(util_.GetInputMethodIdsFromLanguageCodeInternal( language_code_to_ids_map, "invalid_lang", kAllInputMethods, &result)); EXPECT_FALSE(util_.GetInputMethodIdsFromLanguageCodeInternal( language_code_to_ids_map, "invalid_lang", kKeyboardLayoutsOnly, &result)); } // US keyboard + English US UI = US keyboard only. TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_Us_And_EnUs) { const InputMethodDescriptor* descriptor = util_.GetInputMethodDescriptorFromId("xkb:us::eng"); // US keyboard. ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. std::vector input_method_ids; util_.GetFirstLoginInputMethodIds("en-US", *descriptor, &input_method_ids); ASSERT_EQ(1U, input_method_ids.size()); EXPECT_EQ("xkb:us::eng", input_method_ids[0]); } // US keyboard + Chinese UI = US keyboard + Pinyin IME. TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_Us_And_Zh) { const InputMethodDescriptor* descriptor = util_.GetInputMethodDescriptorFromId("xkb:us::eng"); // US keyboard. ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. std::vector input_method_ids; util_.GetFirstLoginInputMethodIds("zh-CN", *descriptor, &input_method_ids); ASSERT_EQ(2U, input_method_ids.size()); EXPECT_EQ("xkb:us::eng", input_method_ids[0]); EXPECT_EQ("pinyin", input_method_ids[1]); // Pinyin for US keybaord. } // Korean keyboard + Korean UI = Korean keyboard + mozc-hangul. TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_KR_And_Ko) { // Korean keyboard const InputMethodDescriptor* descriptor = util_.GetInputMethodDescriptorFromId("xkb:kr:kr104:kor"); ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. std::vector input_method_ids; util_.GetFirstLoginInputMethodIds("ko", *descriptor, &input_method_ids); ASSERT_EQ(2U, input_method_ids.size()); EXPECT_EQ("xkb:kr:kr104:kor", input_method_ids[0]); EXPECT_EQ("mozc-hangul", input_method_ids[1]); // Mozc for JP keybaord. } // US keyboard + Russian UI = US keyboard + Russsian keyboard TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_Us_And_Ru) { const InputMethodDescriptor* descriptor = util_.GetInputMethodDescriptorFromId("xkb:us::eng"); // US keyboard. ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. std::vector input_method_ids; util_.GetFirstLoginInputMethodIds("ru", *descriptor, &input_method_ids); ASSERT_EQ(2U, input_method_ids.size()); EXPECT_EQ("xkb:us::eng", input_method_ids[0]); EXPECT_EQ("xkb:ru::rus", input_method_ids[1]); // Russian keyboard. } // US keyboard + Traditional Chinese = US keyboard + chewing. TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_Us_And_ZhTw) { const InputMethodDescriptor* descriptor = util_.GetInputMethodDescriptorFromId("xkb:us::eng"); // US keyboard. ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. std::vector input_method_ids; util_.GetFirstLoginInputMethodIds("zh-TW", *descriptor, &input_method_ids); ASSERT_EQ(2U, input_method_ids.size()); EXPECT_EQ("xkb:us::eng", input_method_ids[0]); EXPECT_EQ("mozc-chewing", input_method_ids[1]); // Chewing. } // US keyboard + Thai = US keyboard + kesmanee. TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_Us_And_Th) { const InputMethodDescriptor* descriptor = util_.GetInputMethodDescriptorFromId("xkb:us::eng"); // US keyboard. ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. std::vector input_method_ids; util_.GetFirstLoginInputMethodIds("th", *descriptor, &input_method_ids); ASSERT_EQ(2U, input_method_ids.size()); EXPECT_EQ("xkb:us::eng", input_method_ids[0]); EXPECT_EQ("m17n:th:kesmanee", input_method_ids[1]); // Kesmanee. } // US keyboard + Vietnamese = US keyboard + TCVN6064. TEST_F(InputMethodUtilTest, TestGetFirstLoginInputMethodIds_Us_And_Vi) { const InputMethodDescriptor* descriptor = util_.GetInputMethodDescriptorFromId("xkb:us::eng"); // US keyboard. ASSERT_TRUE(NULL != descriptor); // ASSERT_NE doesn't compile. std::vector input_method_ids; util_.GetFirstLoginInputMethodIds("vi", *descriptor, &input_method_ids); ASSERT_EQ(2U, input_method_ids.size()); EXPECT_EQ("xkb:us::eng", input_method_ids[0]); EXPECT_EQ("m17n:vi:tcvn", input_method_ids[1]); // TCVN6064. } TEST_F(InputMethodUtilTest, TestGetLanguageCodesFromInputMethodIds) { std::vector input_method_ids; input_method_ids.push_back("xkb:us::eng"); // English US. input_method_ids.push_back("xkb:us:dvorak:eng"); // English US Dvorak. input_method_ids.push_back("pinyin"); // Pinyin input_method_ids.push_back("xkb:fr::fra"); // French France. std::vector language_codes; util_.GetLanguageCodesFromInputMethodIds(input_method_ids, &language_codes); ASSERT_EQ(3U, language_codes.size()); EXPECT_EQ("en-US", language_codes[0]); EXPECT_EQ("zh-CN", language_codes[1]); EXPECT_EQ("fr", language_codes[2]); } // Test all supported descriptors to detect a typo in ibus_input_methods.txt. TEST_F(InputMethodUtilTest, TestIBusInputMethodText) { for (size_t i = 0; i < util_.supported_input_methods_->size(); ++i) { const std::string language_code = util_.supported_input_methods_->at(i).language_code(); const string16 display_name = l10n_util::GetDisplayNameForLocale(language_code, "en", false); // Only two formats, like "fr" (lower case) and "en-US" (lower-upper), are // allowed. See the text file for details. EXPECT_TRUE(language_code.length() == 2 || (language_code.length() == 5 && language_code[2] == '-')) << "Invalid language code " << language_code; EXPECT_TRUE(l10n_util::IsValidLocaleSyntax(language_code)) << "Invalid language code " << language_code; EXPECT_FALSE(display_name.empty()) << "Invalid language code " << language_code; // On error, GetDisplayNameForLocale() returns the |language_code| as-is. EXPECT_NE(language_code, UTF16ToUTF8(display_name)) << "Invalid language code " << language_code; } } } // namespace input_method } // namespace chromeos