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 "chrome/browser/chromeos/input_method/input_method_util.h"
6
7#include <string>
8
9#include "base/utf_string_conversions.h"
10#include "chrome/browser/chromeos/cros/cros_library.h"
11#include "grit/generated_resources.h"
12#include "testing/gtest/include/gtest/gtest.h"
13#include "ui/base/l10n/l10n_util.h"
14
15namespace chromeos {
16namespace input_method {
17
18class InputMethodUtilTest : public testing::Test {
19 public:
20  static void SetUpTestCase() {
21    // Reload the internal maps before running tests, with the stub
22    // libcros enabled, so that test data is loaded properly.
23    ScopedStubCrosEnabler stub_cros_enabler;
24    ReloadInternalMaps();
25  }
26
27 private:
28  // Ensure we always use the stub libcros in each test.
29  ScopedStubCrosEnabler stub_cros_enabler_;
30};
31
32TEST_F(InputMethodUtilTest, GetStringUTF8) {
33  EXPECT_EQ("Pinyin input method",
34            GetStringUTF8("Pinyin", ""));
35  EXPECT_EQ("Japanese input method (for US Dvorak keyboard)",
36            GetStringUTF8("Mozc (US Dvorak keyboard layout)", ""));
37  EXPECT_EQ("Google Japanese Input (for US Dvorak keyboard)",
38            GetStringUTF8("Google Japanese Input (US Dvorak keyboard layout)",
39                          ""));
40}
41
42TEST_F(InputMethodUtilTest, StringIsSupported) {
43  EXPECT_TRUE(StringIsSupported("Hiragana", "mozc"));
44  EXPECT_TRUE(StringIsSupported("Latin", "mozc"));
45  EXPECT_TRUE(StringIsSupported("Direct input", "mozc"));
46  EXPECT_FALSE(StringIsSupported(
47      "####THIS_STRING_IS_NOT_SUPPORTED####", "mozc"));
48  EXPECT_TRUE(StringIsSupported("Chinese", "pinyin"));
49  EXPECT_TRUE(StringIsSupported("Chinese", "mozc-chewing"));
50  // The string "Chinese" is not for "hangul".
51  EXPECT_FALSE(StringIsSupported("Chinese", "hangul"));
52}
53
54TEST_F(InputMethodUtilTest, NormalizeLanguageCode) {
55  // TODO(yusukes): test all language codes that IBus provides.
56  EXPECT_EQ("ja", NormalizeLanguageCode("ja"));
57  EXPECT_EQ("ja", NormalizeLanguageCode("jpn"));
58  // In the past "t" had a meaning of "other language" for some m17n latin
59  // input methods for testing purpose, but it is no longer used. We test "t"
60  // here as just an "unknown" language.
61  EXPECT_EQ("t", NormalizeLanguageCode("t"));
62  EXPECT_EQ("zh-CN", NormalizeLanguageCode("zh-CN"));
63  EXPECT_EQ("zh-CN", NormalizeLanguageCode("zh_CN"));
64  EXPECT_EQ("en-US", NormalizeLanguageCode("EN_us"));
65  // See app/l10n_util.cc for es-419.
66  EXPECT_EQ("es-419", NormalizeLanguageCode("es_419"));
67
68  // Special three-letter language codes.
69  EXPECT_EQ("cs", NormalizeLanguageCode("cze"));
70  EXPECT_EQ("de", NormalizeLanguageCode("ger"));
71  EXPECT_EQ("el", NormalizeLanguageCode("gre"));
72  EXPECT_EQ("hr", NormalizeLanguageCode("scr"));
73  EXPECT_EQ("ro", NormalizeLanguageCode("rum"));
74  EXPECT_EQ("sk", NormalizeLanguageCode("slo"));
75}
76
77TEST_F(InputMethodUtilTest, IsKeyboardLayout) {
78  EXPECT_TRUE(IsKeyboardLayout("xkb:us::eng"));
79  EXPECT_FALSE(IsKeyboardLayout("mozc"));
80}
81
82TEST_F(InputMethodUtilTest, GetLanguageCodeFromDescriptor) {
83  EXPECT_EQ("ja", GetLanguageCodeFromDescriptor(
84      InputMethodDescriptor("mozc", "Mozc", "us", "ja")));
85  EXPECT_EQ("zh-TW", GetLanguageCodeFromDescriptor(
86      InputMethodDescriptor("mozc-chewing", "Chewing", "us", "zh")));
87  EXPECT_EQ("zh-TW", GetLanguageCodeFromDescriptor(
88      InputMethodDescriptor("m17n:zh:cangjie", "Cangjie", "us", "zh")));
89  EXPECT_EQ("zh-TW", GetLanguageCodeFromDescriptor(
90      InputMethodDescriptor("m17n:zh:quick", "Quick", "us", "zh")));
91  EXPECT_EQ("zh-CN", GetLanguageCodeFromDescriptor(
92      InputMethodDescriptor("pinyin", "Pinyin", "us", "zh")));
93  EXPECT_EQ("en-US", GetLanguageCodeFromDescriptor(
94      InputMethodDescriptor("xkb:us::eng", "USA", "us", "eng")));
95  EXPECT_EQ("en-UK", GetLanguageCodeFromDescriptor(
96      InputMethodDescriptor("xkb:uk::eng", "United Kingdom", "us", "eng")));
97}
98
99TEST_F(InputMethodUtilTest, GetKeyboardLayoutName) {
100  // Unsupported case.
101  EXPECT_EQ("", GetKeyboardLayoutName("UNSUPPORTED_ID"));
102
103  // Supported cases (samples).
104  EXPECT_EQ("jp", GetKeyboardLayoutName("mozc-jp"));
105  EXPECT_EQ("us", GetKeyboardLayoutName("pinyin"));
106  EXPECT_EQ("us", GetKeyboardLayoutName("m17n:ar:kbd"));
107  EXPECT_EQ("es", GetKeyboardLayoutName("xkb:es::spa"));
108  EXPECT_EQ("es(cat)", GetKeyboardLayoutName("xkb:es:cat:cat"));
109  EXPECT_EQ("gb(extd)", GetKeyboardLayoutName("xkb:gb:extd:eng"));
110  EXPECT_EQ("us", GetKeyboardLayoutName("xkb:us::eng"));
111  EXPECT_EQ("us(dvorak)", GetKeyboardLayoutName("xkb:us:dvorak:eng"));
112  EXPECT_EQ("us(colemak)", GetKeyboardLayoutName("xkb:us:colemak:eng"));
113  EXPECT_EQ("de(neo)", GetKeyboardLayoutName("xkb:de:neo:ger"));
114}
115
116TEST_F(InputMethodUtilTest, GetLanguageCodeFromInputMethodId) {
117  // Make sure that the -CN is added properly.
118  EXPECT_EQ("zh-CN", GetLanguageCodeFromInputMethodId("pinyin"));
119}
120
121TEST_F(InputMethodUtilTest, GetInputMethodDisplayNameFromId) {
122  EXPECT_EQ("Pinyin input method", GetInputMethodDisplayNameFromId("pinyin"));
123  EXPECT_EQ("US keyboard",
124            GetInputMethodDisplayNameFromId("xkb:us::eng"));
125  EXPECT_EQ("", GetInputMethodDisplayNameFromId("nonexistent"));
126}
127
128TEST_F(InputMethodUtilTest, GetInputMethodDescriptorFromId) {
129  EXPECT_EQ(NULL, GetInputMethodDescriptorFromId("non_existent"));
130
131  const InputMethodDescriptor* descriptor =
132      GetInputMethodDescriptorFromId("pinyin");
133  ASSERT_TRUE(NULL != descriptor);  // ASSERT_NE doesn't compile.
134  EXPECT_EQ("pinyin", descriptor->id);
135  EXPECT_EQ("Pinyin", descriptor->display_name);
136  EXPECT_EQ("us", descriptor->keyboard_layout);
137  // This is not zh-CN as the language code in InputMethodDescriptor is
138  // not normalized to our format. The normalization is done in
139  // GetLanguageCodeFromDescriptor().
140  EXPECT_EQ("zh", descriptor->language_code);
141}
142
143TEST_F(InputMethodUtilTest, GetLanguageNativeDisplayNameFromCode) {
144  EXPECT_EQ(UTF8ToUTF16("suomi"), GetLanguageNativeDisplayNameFromCode("fi"));
145}
146
147TEST_F(InputMethodUtilTest, SortLanguageCodesByNames) {
148  std::vector<std::string> language_codes;
149  // Check if this function can handle an empty list.
150  SortLanguageCodesByNames(&language_codes);
151
152  language_codes.push_back("ja");
153  language_codes.push_back("fr");
154  // For "t", see the comment in NormalizeLanguageCode test.
155  language_codes.push_back("t");
156  SortLanguageCodesByNames(&language_codes);
157  ASSERT_EQ(3U, language_codes.size());
158  ASSERT_EQ("fr", language_codes[0]);  // French
159  ASSERT_EQ("ja", language_codes[1]);  // Japanese
160  ASSERT_EQ("t",  language_codes[2]);  // Others
161
162  // Add a duplicate entry and see if it works.
163  language_codes.push_back("ja");
164  SortLanguageCodesByNames(&language_codes);
165  ASSERT_EQ(4U, language_codes.size());
166  ASSERT_EQ("fr", language_codes[0]);  // French
167  ASSERT_EQ("ja", language_codes[1]);  // Japanese
168  ASSERT_EQ("ja", language_codes[2]);  // Japanese
169  ASSERT_EQ("t",  language_codes[3]);  // Others
170}
171
172TEST_F(InputMethodUtilTest, GetInputMethodIdsForLanguageCode) {
173  std::multimap<std::string, std::string> language_code_to_ids_map;
174  language_code_to_ids_map.insert(std::make_pair("ja", "mozc"));
175  language_code_to_ids_map.insert(std::make_pair("ja", "mozc-jp"));
176  language_code_to_ids_map.insert(std::make_pair("ja", "xkb:jp:jpn"));
177  language_code_to_ids_map.insert(std::make_pair("fr", "xkb:fr:fra"));
178
179  std::vector<std::string> result;
180  EXPECT_TRUE(GetInputMethodIdsFromLanguageCodeInternal(
181      language_code_to_ids_map, "ja", kAllInputMethods, &result));
182  EXPECT_EQ(3U, result.size());
183  EXPECT_TRUE(GetInputMethodIdsFromLanguageCodeInternal(
184      language_code_to_ids_map, "ja", kKeyboardLayoutsOnly, &result));
185  ASSERT_EQ(1U, result.size());
186  EXPECT_EQ("xkb:jp:jpn", result[0]);
187
188  EXPECT_TRUE(GetInputMethodIdsFromLanguageCodeInternal(
189      language_code_to_ids_map, "fr", kAllInputMethods, &result));
190  ASSERT_EQ(1U, result.size());
191  EXPECT_EQ("xkb:fr:fra", result[0]);
192  EXPECT_TRUE(GetInputMethodIdsFromLanguageCodeInternal(
193      language_code_to_ids_map, "fr", kKeyboardLayoutsOnly, &result));
194  ASSERT_EQ(1U, result.size());
195  EXPECT_EQ("xkb:fr:fra", result[0]);
196
197  EXPECT_FALSE(GetInputMethodIdsFromLanguageCodeInternal(
198      language_code_to_ids_map, "invalid_lang", kAllInputMethods, &result));
199  EXPECT_FALSE(GetInputMethodIdsFromLanguageCodeInternal(
200      language_code_to_ids_map, "invalid_lang", kKeyboardLayoutsOnly, &result));
201}
202
203// US keyboard + English US UI = US keyboard only.
204TEST_F(InputMethodUtilTest, GetFirstLoginInputMethodIds_Us_And_EnUs) {
205  const InputMethodDescriptor* descriptor =
206      GetInputMethodDescriptorFromId("xkb:us::eng");  // US keyboard.
207  ASSERT_TRUE(NULL != descriptor);  // ASSERT_NE doesn't compile.
208  std::vector<std::string> input_method_ids;
209  GetFirstLoginInputMethodIds("en-US", *descriptor, &input_method_ids);
210  ASSERT_EQ(1U, input_method_ids.size());
211  EXPECT_EQ("xkb:us::eng", input_method_ids[0]);
212}
213
214// US keyboard + Japanese UI = US keyboard + mozc.
215TEST_F(InputMethodUtilTest, GetFirstLoginInputMethodIds_Us_And_Ja) {
216  const InputMethodDescriptor* descriptor =
217      GetInputMethodDescriptorFromId("xkb:us::eng");  // US keyboard.
218  ASSERT_TRUE(NULL != descriptor);  // ASSERT_NE doesn't compile.
219  std::vector<std::string> input_method_ids;
220  GetFirstLoginInputMethodIds("ja", *descriptor, &input_method_ids);
221  ASSERT_EQ(2U, input_method_ids.size());
222  EXPECT_EQ("xkb:us::eng", input_method_ids[0]);
223  EXPECT_EQ("mozc", input_method_ids[1]);  // Mozc for US keybaord.
224}
225
226// JP keyboard + Japanese UI = JP keyboard + mozc-jp.
227TEST_F(InputMethodUtilTest, GetFirstLoginInputMethodIds_JP_And_Ja) {
228  const InputMethodDescriptor* descriptor =
229      GetInputMethodDescriptorFromId("xkb:jp::jpn");  // Japanese keyboard.
230  ASSERT_TRUE(NULL != descriptor);  // ASSERT_NE doesn't compile.
231  std::vector<std::string> input_method_ids;
232  GetFirstLoginInputMethodIds("ja", *descriptor, &input_method_ids);
233  ASSERT_EQ(2U, input_method_ids.size());
234  EXPECT_EQ("xkb:jp::jpn", input_method_ids[0]);
235  EXPECT_EQ("mozc-jp", input_method_ids[1]);  // Mozc for JP keybaord.
236}
237
238// US dvorak keyboard + Japanese UI = US dvorak keyboard + mozc-dv.
239TEST_F(InputMethodUtilTest, GetFirstLoginInputMethodIds_Dvorak_And_Ja) {
240  const InputMethodDescriptor* descriptor =
241      GetInputMethodDescriptorFromId("xkb:us:dvorak:eng");  // US Drovak keyboard.
242  ASSERT_TRUE(NULL != descriptor);  // ASSERT_NE doesn't compile.
243  std::vector<std::string> input_method_ids;
244  GetFirstLoginInputMethodIds("ja", *descriptor, &input_method_ids);
245  ASSERT_EQ(2U, input_method_ids.size());
246  EXPECT_EQ("xkb:us:dvorak:eng", input_method_ids[0]);
247  EXPECT_EQ("mozc-dv", input_method_ids[1]);  // Mozc for US Dvorak keybaord.
248}
249
250// US keyboard + Russian UI = US keyboard + Russsian keyboard
251TEST_F(InputMethodUtilTest, GetFirstLoginInputMethodIds_Us_And_Ru) {
252  const InputMethodDescriptor* descriptor =
253      GetInputMethodDescriptorFromId("xkb:us::eng");  // US keyboard.
254  ASSERT_TRUE(NULL != descriptor);  // ASSERT_NE doesn't compile.
255  std::vector<std::string> input_method_ids;
256  GetFirstLoginInputMethodIds("ru", *descriptor, &input_method_ids);
257  ASSERT_EQ(2U, input_method_ids.size());
258  EXPECT_EQ("xkb:us::eng", input_method_ids[0]);
259  EXPECT_EQ("xkb:ru::rus", input_method_ids[1]);  // Russian keyboard.
260}
261
262// US keyboard + Traditional Chinese = US keyboard + chewing.
263TEST_F(InputMethodUtilTest, GetFirstLoginInputMethodIds_Us_And_ZhTw) {
264  const InputMethodDescriptor* descriptor =
265      GetInputMethodDescriptorFromId("xkb:us::eng");  // US keyboard.
266  ASSERT_TRUE(NULL != descriptor);  // ASSERT_NE doesn't compile.
267  std::vector<std::string> input_method_ids;
268  GetFirstLoginInputMethodIds("zh-TW", *descriptor, &input_method_ids);
269  ASSERT_EQ(2U, input_method_ids.size());
270  EXPECT_EQ("xkb:us::eng", input_method_ids[0]);
271  EXPECT_EQ("mozc-chewing", input_method_ids[1]);  // Chewing.
272}
273
274// US keyboard + Thai = US keyboard + kesmanee.
275TEST_F(InputMethodUtilTest, GetFirstLoginInputMethodIds_Us_And_Th) {
276  const InputMethodDescriptor* descriptor =
277      GetInputMethodDescriptorFromId("xkb:us::eng");  // US keyboard.
278  ASSERT_TRUE(NULL != descriptor);  // ASSERT_NE doesn't compile.
279  std::vector<std::string> input_method_ids;
280  GetFirstLoginInputMethodIds("th", *descriptor, &input_method_ids);
281  ASSERT_EQ(2U, input_method_ids.size());
282  EXPECT_EQ("xkb:us::eng", input_method_ids[0]);
283  EXPECT_EQ("m17n:th:kesmanee", input_method_ids[1]);  // Kesmanee.
284}
285
286// US keyboard + Vietnamese = US keyboard + TCVN6064.
287TEST_F(InputMethodUtilTest, GetFirstLoginInputMethodIds_Us_And_Vi) {
288  const InputMethodDescriptor* descriptor =
289      GetInputMethodDescriptorFromId("xkb:us::eng");  // US keyboard.
290  ASSERT_TRUE(NULL != descriptor);  // ASSERT_NE doesn't compile.
291  std::vector<std::string> input_method_ids;
292  GetFirstLoginInputMethodIds("vi", *descriptor, &input_method_ids);
293  ASSERT_EQ(2U, input_method_ids.size());
294  EXPECT_EQ("xkb:us::eng", input_method_ids[0]);
295  EXPECT_EQ("m17n:vi:tcvn", input_method_ids[1]);  // TCVN6064.
296}
297
298TEST_F(InputMethodUtilTest, GetLanguageCodesFromInputMethodIds) {
299  std::vector<std::string> input_method_ids;
300  input_method_ids.push_back("xkb:us::eng");  // English US.
301  input_method_ids.push_back("xkb:us:dvorak:eng");  // English US Dvorak.
302  input_method_ids.push_back("mozc-jp");  // Japanese.
303  input_method_ids.push_back("xkb:fr::fra");  // French France.
304  std::vector<std::string> language_codes;
305  GetLanguageCodesFromInputMethodIds(input_method_ids, &language_codes);
306  ASSERT_EQ(3U, language_codes.size());
307  EXPECT_EQ("en-US", language_codes[0]);
308  EXPECT_EQ("ja", language_codes[1]);
309  EXPECT_EQ("fr", language_codes[2]);
310}
311
312}  // namespace input_method
313}  // namespace chromeos
314