1// Copyright 2014 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/ui/webui/chromeos/login/l10n_util.h"
6
7#include "base/at_exit.h"
8#include "base/basictypes.h"
9#include "base/compiler_specific.h"
10#include "base/macros.h"
11#include "base/memory/singleton.h"
12#include "base/message_loop/message_loop.h"
13#include "base/values.h"
14#include "chrome/browser/chromeos/customization_document.h"
15#include "chrome/browser/chromeos/input_method/input_method_configuration.h"
16#include "chrome/browser/ui/webui/chromeos/login/l10n_util_test_util.h"
17#include "chromeos/ime/component_extension_ime_manager.h"
18#include "chromeos/system/statistics_provider.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21namespace chromeos {
22
23namespace {
24
25class MachineStatisticsInitializer {
26 public:
27  MachineStatisticsInitializer();
28
29  static MachineStatisticsInitializer* GetInstance();
30
31 private:
32  DISALLOW_COPY_AND_ASSIGN(MachineStatisticsInitializer);
33};
34
35MachineStatisticsInitializer::MachineStatisticsInitializer() {
36  base::MessageLoop loop;
37  chromeos::system::StatisticsProvider::GetInstance()->
38      StartLoadingMachineStatistics(loop.message_loop_proxy(), false);
39  loop.RunUntilIdle();
40}
41
42// static
43MachineStatisticsInitializer* MachineStatisticsInitializer::GetInstance() {
44  return Singleton<MachineStatisticsInitializer>::get();
45}
46
47void VerifyOnlyUILanguages(const base::ListValue& list) {
48  for (size_t i = 0; i < list.GetSize(); ++i) {
49    const base::DictionaryValue* dict;
50    ASSERT_TRUE(list.GetDictionary(i, &dict));
51    std::string code;
52    ASSERT_TRUE(dict->GetString("code", &code));
53    EXPECT_NE("is", code)
54        << "Icelandic is an example language which has input method "
55        << "but can't use it as UI language.";
56  }
57}
58
59void VerifyLanguageCode(const base::ListValue& list,
60                        size_t index,
61                        const std::string& expected_code) {
62  const base::DictionaryValue* dict;
63  ASSERT_TRUE(list.GetDictionary(index, &dict));
64  std::string actual_code;
65  ASSERT_TRUE(dict->GetString("code", &actual_code));
66  EXPECT_EQ(expected_code, actual_code)
67      << "Wrong language code at index " << index << ".";
68}
69
70}  // namespace
71
72class L10nUtilTest : public testing::Test {
73 public:
74  L10nUtilTest();
75  virtual ~L10nUtilTest();
76
77  // testing::Test:
78  virtual void SetUp() OVERRIDE;
79  virtual void TearDown() OVERRIDE;
80
81  void SetInputMethods1();
82  void SetInputMethods2();
83
84 private:
85  base::ShadowingAtExitManager at_exit_manager_;
86
87  MockInputMethodManagerWithInputMethods* input_manager_;
88};
89
90L10nUtilTest::L10nUtilTest()
91    : input_manager_(new MockInputMethodManagerWithInputMethods) {
92}
93
94L10nUtilTest::~L10nUtilTest() {
95}
96
97void L10nUtilTest::SetUp() {
98  chromeos::input_method::InitializeForTesting(input_manager_);
99  input_manager_->SetComponentExtensionIMEManager(
100      make_scoped_ptr(new ComponentExtensionIMEManager));
101  MachineStatisticsInitializer::GetInstance();  // Ignore result.
102}
103
104void L10nUtilTest::TearDown() {
105  chromeos::input_method::Shutdown();
106}
107
108void L10nUtilTest::SetInputMethods1() {
109  input_manager_->AddInputMethod("xkb:us::eng", "us", "en-US");
110  input_manager_->AddInputMethod("xkb:fr::fra", "fr", "fr");
111  input_manager_->AddInputMethod("xkb:be::fra", "be", "fr");
112  input_manager_->AddInputMethod("xkb:is::ice", "is", "is");
113}
114
115void L10nUtilTest::SetInputMethods2() {
116  input_manager_->AddInputMethod("xkb:us::eng", "us", "en-US");
117  input_manager_->AddInputMethod("xkb:ch:fr:fra", "ch(fr)", "fr");
118  input_manager_->AddInputMethod("xkb:ch::ger", "ch", "de");
119  input_manager_->AddInputMethod("xkb:it::ita", "it", "it");
120  input_manager_->AddInputMethod("xkb:is::ice", "is", "is");
121}
122
123TEST_F(L10nUtilTest, GetUILanguageList) {
124  SetInputMethods1();
125
126  // This requires initialized StatisticsProvider (see L10nUtilTest()).
127  scoped_ptr<base::ListValue> list(GetUILanguageList(NULL, std::string()));
128
129  VerifyOnlyUILanguages(*list);
130}
131
132TEST_F(L10nUtilTest, FindMostRelevantLocale) {
133  base::ListValue available_locales;
134  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
135  dict->SetString("value", "de");
136  available_locales.Append(dict.release());
137  dict.reset(new base::DictionaryValue);
138  dict->SetString("value", "fr");
139  available_locales.Append(dict.release());
140  dict.reset(new base::DictionaryValue);
141  dict->SetString("value", "en-GB");
142  available_locales.Append(dict.release());
143
144  std::vector<std::string> most_relevant_language_codes;
145  EXPECT_EQ("en-US", FindMostRelevantLocale(most_relevant_language_codes,
146                                            available_locales,
147                                            "en-US"));
148
149  most_relevant_language_codes.push_back("xx");
150  EXPECT_EQ("en-US", FindMostRelevantLocale(most_relevant_language_codes,
151                                            available_locales,
152                                            "en-US"));
153
154  most_relevant_language_codes.push_back("fr");
155  EXPECT_EQ("fr", FindMostRelevantLocale(most_relevant_language_codes,
156                                         available_locales,
157                                         "en-US"));
158
159  most_relevant_language_codes.push_back("de");
160  EXPECT_EQ("fr", FindMostRelevantLocale(most_relevant_language_codes,
161                                         available_locales,
162                                         "en-US"));
163}
164
165void InitStartupCustomizationDocumentForTesting(const std::string& manifest) {
166  StartupCustomizationDocument::GetInstance()->LoadManifestFromString(manifest);
167  StartupCustomizationDocument::GetInstance()->Init(
168      chromeos::system::StatisticsProvider::GetInstance());
169}
170
171const char kStartupManifest[] =
172    "{\n"
173    "  \"version\": \"1.0\",\n"
174    "  \"initial_locale\" : \"fr,en-US,de,is,it\",\n"
175    "  \"initial_timezone\" : \"Europe/Zurich\",\n"
176    "  \"keyboard_layout\" : \"xkb:ch:fr:fra\",\n"
177    "  \"registration_url\" : \"http://www.google.com\",\n"
178    "  \"setup_content\" : {\n"
179    "    \"default\" : {\n"
180    "      \"help_page\" : \"file:///opt/oem/help/en-US/help.html\",\n"
181    "      \"eula_page\" : \"file:///opt/oem/eula/en-US/eula.html\",\n"
182    "    },\n"
183    "  },"
184    "}";
185
186TEST_F(L10nUtilTest, GetUILanguageListMulti) {
187  InitStartupCustomizationDocumentForTesting(kStartupManifest);
188  SetInputMethods2();
189
190  // This requires initialized StatisticsProvider (see L10nUtilTest()).
191  scoped_ptr<base::ListValue> list(GetUILanguageList(NULL, std::string()));
192
193  VerifyOnlyUILanguages(*list);
194
195  // (4 languages (except Icelandic) + divider) = 5 + all other languages
196  ASSERT_LE(5u, list->GetSize());
197
198  VerifyLanguageCode(*list, 0, "fr");
199  VerifyLanguageCode(*list, 1, "en-US");
200  VerifyLanguageCode(*list, 2, "de");
201  VerifyLanguageCode(*list, 3, "it");
202  VerifyLanguageCode(*list, 4, kMostRelevantLanguagesDivider);
203}
204
205TEST_F(L10nUtilTest, GetUILanguageListWithMostRelevant) {
206  std::vector<std::string> most_relevant_language_codes;
207  most_relevant_language_codes.push_back("it");
208  most_relevant_language_codes.push_back("de");
209  most_relevant_language_codes.push_back("nonexistent");
210
211  // This requires initialized StatisticsProvider (see L10nUtilTest()).
212  scoped_ptr<base::ListValue>
213      list(GetUILanguageList(&most_relevant_language_codes, std::string()));
214
215  VerifyOnlyUILanguages(*list);
216
217  ASSERT_LE(3u, list->GetSize());
218
219  VerifyLanguageCode(*list, 0, "it");
220  VerifyLanguageCode(*list, 1, "de");
221  VerifyLanguageCode(*list, 2, kMostRelevantLanguagesDivider);
222}
223
224}  // namespace chromeos
225