oobe_localization_browsertest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 "base/message_loop/message_loop.h" 6#include "base/prefs/pref_service.h" 7#include "base/strings/stringprintf.h" 8#include "base/task_runner.h" 9#include "chrome/browser/browser_process.h" 10#include "chrome/browser/chrome_notification_types.h" 11#include "chrome/browser/chromeos/customization_document.h" 12#include "chrome/browser/chromeos/login/login_display_host_impl.h" 13#include "chrome/browser/chromeos/login/login_wizard.h" 14#include "chrome/browser/chromeos/login/test/js_checker.h" 15#include "chrome/common/pref_names.h" 16#include "chrome/test/base/in_process_browser_test.h" 17#include "chromeos/system/statistics_provider.h" 18#include "content/public/browser/notification_service.h" 19#include "content/public/browser/web_contents.h" 20#include "content/public/test/browser_test_utils.h" 21#include "content/public/test/test_utils.h" 22 23namespace base { 24class TaskRunner; 25} 26 27namespace chromeos { 28 29namespace { 30 31// OOBE constants. 32const char* kLocaleSelect = "language-select"; 33const char* kKeyboardSelect = "keyboard-select"; 34 35const char* kUSLayout = "xkb:us::eng"; 36 37} 38 39namespace system { 40 41// Custom StatisticsProvider that will return each set of region settings. 42class FakeStatisticsProvider : public StatisticsProvider { 43 public: 44 virtual ~FakeStatisticsProvider() {} 45 46 void set_locale(const std::string& locale) { 47 initial_locale_ = locale; 48 } 49 50 void set_keyboard_layout(const std::string& keyboard_layout) { 51 keyboard_layout_ = keyboard_layout; 52 } 53 54 private: 55 // StatisticsProvider overrides. 56 virtual void StartLoadingMachineStatistics( 57 const scoped_refptr<base::TaskRunner>& file_task_runner, 58 bool load_oem_manifest) OVERRIDE { 59 } 60 61 // Populates the named machine statistic for initial_locale and 62 // keyboard_layout only. 63 virtual bool GetMachineStatistic(const std::string& name, 64 std::string* result) OVERRIDE { 65 if (name == "initial_locale") 66 *result = initial_locale_; 67 else if (name == "keyboard_layout") 68 *result = keyboard_layout_; 69 else 70 return false; 71 72 return true; 73 } 74 75 virtual bool GetMachineFlag(const std::string& name, bool* result) OVERRIDE { 76 return false; 77 } 78 79 virtual void Shutdown() OVERRIDE { 80 } 81 82 std::string initial_locale_; 83 std::string keyboard_layout_; 84}; 85 86} // namespace system 87 88class OobeLocalizationTest : public InProcessBrowserTest { 89 public: 90 OobeLocalizationTest(); 91 92 // Verifies that the comma-separated |values| corresponds with the first 93 // values in |select_id|, optionally checking for an options group label after 94 // the first set of options. 95 void VerifyInitialOptions(const char* select_id, 96 const char* values, 97 bool check_separator); 98 99 // Verifies that |value| exists in |select_id|. 100 void VerifyOptionExists(const char* select_id, const char* value); 101 102 // Dumps OOBE select control (language or keyboard) to string. 103 std::string DumpOptions(const char* select_id); 104 105 protected: 106 // Runs the test for the given locale and keyboard layout. 107 void RunLocalizationTest(const std::string& initial_locale, 108 const std::string& keyboard_layout, 109 const std::string& expected_locale, 110 const std::string& expected_keyboard_layout, 111 const std::string& expected_keyboard_select_control); 112 113 private: 114 scoped_ptr<system::FakeStatisticsProvider> statistics_provider_; 115 test::JSChecker checker; 116 117 DISALLOW_COPY_AND_ASSIGN(OobeLocalizationTest); 118}; 119 120OobeLocalizationTest::OobeLocalizationTest() { 121 statistics_provider_.reset(new system::FakeStatisticsProvider()); 122 // Set the instance returned by GetInstance() for testing. 123 system::StatisticsProvider::SetTestProvider(statistics_provider_.get()); 124} 125 126void OobeLocalizationTest::VerifyInitialOptions(const char* select_id, 127 const char* values, 128 bool check_separator) { 129 const std::string expression = base::StringPrintf( 130 "(function () {\n" 131 " var select = document.querySelector('#%s');\n" 132 " if (!select)\n" 133 " return false;\n" 134 " var values = '%s'.split(',');\n" 135 " var correct = select.selectedIndex == 0;\n" 136 " for (var i = 0; i < values.length && correct; i++) {\n" 137 " if (select.options[i].value != values[i])\n" 138 " correct = false;\n" 139 " }\n" 140 " if (%d && correct)\n" 141 " correct = select.children[values.length].tagName === 'OPTGROUP';\n" 142 " return correct;\n" 143 "})()", select_id, values, check_separator); 144 ASSERT_TRUE(checker.GetBool(expression)) << expression; 145} 146 147void OobeLocalizationTest::VerifyOptionExists(const char* select_id, 148 const char* value) { 149 const std::string expression = base::StringPrintf( 150 "(function () {\n" 151 " var select = document.querySelector('#%s');\n" 152 " if (!select)\n" 153 " return false;\n" 154 " for (var i = 0; i < select.options.length; i++) {\n" 155 " if (select.options[i].value == '%s')\n" 156 " return true;\n" 157 " }\n" 158 " return false;\n" 159 "})()", select_id, value); 160 ASSERT_TRUE(checker.GetBool(expression)) << expression; 161} 162 163std::string OobeLocalizationTest::DumpOptions(const char* select_id) { 164 const std::string expression = base::StringPrintf( 165 "\n" 166 "(function () {\n" 167 " var selector = '#%s';\n" 168 " var divider = ',';\n" 169 " var select = document.querySelector(selector);\n" 170 " if (!select)\n" 171 " return 'document.querySelector(' + selector + ') failed.';\n" 172 " var dumpOptgroup = function(group) {\n" 173 " var result = '';\n" 174 " for (var i = 0; i < group.children.length; i++) {\n" 175 " if (i > 0) {\n" 176 " result += divider;\n" 177 " }\n" 178 " if (group.children[i].value) {\n" 179 " result += group.children[i].value;\n" 180 " } else {\n" 181 " result += '__NO_VALUE__';\n" 182 " }\n" 183 " }\n" 184 " return result;\n" 185 " };\n" 186 " var result = '';\n" 187 " var children = select.children;\n" 188 " for (var i = 0; i < children.length; i++) {\n" 189 " if (i > 0) {\n" 190 " result += divider;\n" 191 " }\n" 192 " if (children[i].value) {\n" 193 " result += children[i].value;\n" 194 " } else if (children[i].tagName === 'OPTGROUP') {\n" 195 " result += '[' + dumpOptgroup(children[i]) + ']';\n" 196 " } else {\n" 197 " result += '__NO_VALUE__';\n" 198 " }\n" 199 " }\n" 200 " return result;\n" 201 "})()\n", 202 select_id); 203 return checker.GetString(expression); 204} 205 206void OobeLocalizationTest::RunLocalizationTest( 207 const std::string& initial_locale, 208 const std::string& keyboard_layout, 209 const std::string& expected_locale, 210 const std::string& expected_keyboard_layout, 211 const std::string& expected_keyboard_select_control) { 212 statistics_provider_->set_locale(initial_locale); 213 statistics_provider_->set_keyboard_layout(keyboard_layout); 214 215 // Initialize StartupCustomizationDocument with fake statistics provider. 216 StartupCustomizationDocument::GetInstance()->Init( 217 statistics_provider_.get()); 218 219 // Bring up the OOBE network screen. 220 chromeos::ShowLoginWizard(chromeos::WizardController::kNetworkScreenName); 221 content::WindowedNotificationObserver( 222 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, 223 content::NotificationService::AllSources()).Wait(); 224 225 checker.set_web_contents(static_cast<chromeos::LoginDisplayHostImpl*>( 226 chromeos::LoginDisplayHostImpl::default_host())-> 227 GetOobeUI()->web_ui()->GetWebContents()); 228 229 VerifyInitialOptions(kLocaleSelect, expected_locale.c_str(), true); 230 VerifyInitialOptions(kKeyboardSelect, 231 expected_keyboard_layout.c_str(), 232 false); 233 234 // Make sure we have a fallback keyboard. 235 VerifyOptionExists(kKeyboardSelect, kUSLayout); 236 237 // Note, that sort order is locale-specific, but is unlikely to change. 238 // Especially for keyboard layouts. 239 EXPECT_EQ(expected_keyboard_select_control, DumpOptions(kKeyboardSelect)); 240 241 // Shut down the display host. 242 chromeos::LoginDisplayHostImpl::default_host()->Finalize(); 243 base::MessageLoopForUI::current()->RunUntilIdle(); 244 245 // Clear the locale pref so the statistics provider is pinged next time. 246 g_browser_process->local_state()->SetString(prefs::kApplicationLocale, 247 std::string()); 248} 249 250IN_PROC_BROWSER_TEST_F(OobeLocalizationTest, NetworkScreenNonLatin) { 251 // For a non-Latin keyboard layout like Russian, we expect to see the US 252 // keyboard. 253 RunLocalizationTest("ru", "xkb:ru::rus", 254 "ru", kUSLayout, 255 "xkb:us::eng"); 256 257 RunLocalizationTest("ru", "xkb:us::eng,xkb:ru::rus", 258 "ru", kUSLayout, 259 "xkb:us::eng"); 260 261 // IMEs do not load at OOBE, so we just expect to see the (Latin) Japanese 262 // keyboard. 263 RunLocalizationTest("ja", "xkb:jp::jpn", 264 "ja", "xkb:jp::jpn", 265 "xkb:jp::jpn,[xkb:us::eng]"); 266} 267 268IN_PROC_BROWSER_TEST_F(OobeLocalizationTest, NetworkScreenKeyboardLayout) { 269 // We don't use the Icelandic locale but the Icelandic keyboard layout 270 // should still be selected when specified as the default. 271 RunLocalizationTest("en-US", "xkb:is::ice", 272 "en-US", "xkb:is::ice", 273 "xkb:is::ice,[" 274 "xkb:us::eng,xkb:us:intl:eng,xkb:us:altgr-intl:eng," 275 "xkb:us:dvorak:eng,xkb:us:colemak:eng]"); 276} 277 278IN_PROC_BROWSER_TEST_F(OobeLocalizationTest, NetworkScreenFullLatin) { 279 // French Swiss keyboard. 280 RunLocalizationTest("fr", "xkb:ch:fr:fra", 281 "fr", "xkb:ch:fr:fra", 282 "xkb:ch:fr:fra,[" 283 "xkb:fr::fra,xkb:be::fra,xkb:ca::fra," 284 "xkb:ca:multix:fra,xkb:us::eng]"); 285 286 // German Swiss keyboard. 287 RunLocalizationTest("de", "xkb:ch::ger", 288 "de", "xkb:ch::ger", 289 "xkb:ch::ger,[" 290 "xkb:de::ger,xkb:de:neo:ger,xkb:be::ger,xkb:us::eng" 291 "]"); 292} 293 294IN_PROC_BROWSER_TEST_F(OobeLocalizationTest, NetworkScreenMultipleLocales) { 295 RunLocalizationTest("es,en-US,nl", "xkb:be::nld", 296 "es,en-US,nl", "xkb:be::nld", 297 "xkb:be::nld,[xkb:es::spa,xkb:latam::spa,xkb:us::eng]"); 298 299 RunLocalizationTest("ru,de", "xkb:ru::rus", 300 "ru,de", kUSLayout, 301 "xkb:us::eng"); 302} 303 304} // namespace chromeos 305