OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/spellchecker/spellcheck_service.h" | 5 #include "chrome/browser/spellchecker/spellcheck_service.h" |
6 | 6 |
7 #include <stddef.h> | |
8 #include <stdint.h> | |
9 #include <string> | 7 #include <string> |
10 #include <tuple> | |
11 #include <vector> | 8 #include <vector> |
12 | 9 |
13 #include "base/command_line.h" | |
14 #include "base/macros.h" | 10 #include "base/macros.h" |
15 #include "base/path_service.h" | 11 #include "base/path_service.h" |
16 #include "base/run_loop.h" | 12 #include "base/run_loop.h" |
17 #include "base/strings/string_piece.h" | 13 #include "base/strings/string_piece.h" |
18 #include "base/strings/string_split.h" | 14 #include "base/strings/string_split.h" |
19 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
| 16 #include "base/strings/utf_string_conversions.h" |
20 #include "base/synchronization/waitable_event.h" | 17 #include "base/synchronization/waitable_event.h" |
| 18 #include "base/test/histogram_tester.h" |
21 #include "base/threading/thread_restrictions.h" | 19 #include "base/threading/thread_restrictions.h" |
22 #include "base/values.h" | 20 #include "base/values.h" |
23 #include "chrome/browser/profiles/profile.h" | 21 #include "chrome/browser/profiles/profile.h" |
24 #include "chrome/browser/spellchecker/spellcheck_factory.h" | 22 #include "chrome/browser/spellchecker/spellcheck_factory.h" |
| 23 #include "chrome/browser/spellchecker/spellcheck_host_impl.h" |
| 24 #include "chrome/browser/spellchecker/spellcheck_service.h" |
25 #include "chrome/browser/ui/browser.h" | 25 #include "chrome/browser/ui/browser.h" |
26 #include "chrome/common/chrome_paths.h" | 26 #include "chrome/common/chrome_paths.h" |
27 #include "chrome/common/chrome_switches.h" | |
28 #include "chrome/common/pref_names.h" | 27 #include "chrome/common/pref_names.h" |
29 #include "chrome/test/base/in_process_browser_test.h" | 28 #include "chrome/test/base/in_process_browser_test.h" |
30 #include "components/prefs/pref_service.h" | 29 #include "components/prefs/pref_service.h" |
31 #include "components/spellcheck/browser/pref_names.h" | 30 #include "components/spellcheck/browser/pref_names.h" |
32 #include "components/spellcheck/common/spellcheck.mojom.h" | 31 #include "components/spellcheck/common/spellcheck.mojom.h" |
33 #include "components/spellcheck/common/spellcheck_common.h" | 32 #include "components/spellcheck/common/spellcheck_common.h" |
| 33 #include "components/spellcheck/common/spellcheck_result.h" |
34 #include "components/user_prefs/user_prefs.h" | 34 #include "components/user_prefs/user_prefs.h" |
35 #include "content/public/test/mock_render_process_host.h" | 35 #include "content/public/test/mock_render_process_host.h" |
36 #include "content/public/test/test_utils.h" | 36 #include "content/public/test/test_utils.h" |
37 #include "url/gurl.h" | 37 #include "services/service_manager/public/cpp/bind_source_info.h" |
38 | 38 |
39 using content::BrowserContext; | 39 using content::BrowserContext; |
40 | 40 using content::RenderProcessHost; |
41 namespace { | |
42 | |
43 // A corrupted BDICT data used in DeleteCorruptedBDICT. Please do not use this | |
44 // BDICT data for other tests. | |
45 const uint8_t kCorruptedBDICT[] = { | |
46 0x42, 0x44, 0x69, 0x63, 0x02, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, | |
47 0x3b, 0x00, 0x00, 0x00, 0x65, 0x72, 0xe0, 0xac, 0x27, 0xc7, 0xda, 0x66, | |
48 0x6d, 0x1e, 0xa6, 0x35, 0xd1, 0xf6, 0xb7, 0x35, 0x32, 0x00, 0x00, 0x00, | |
49 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, | |
50 0x0a, 0x0a, 0x41, 0x46, 0x20, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, | |
51 0x49, 0x00, 0x68, 0x02, 0x73, 0x06, 0x74, 0x0b, 0x77, 0x11, 0x79, 0x15, | |
52 }; | |
53 | |
54 } // namespace | |
55 | 41 |
56 class SpellcheckServiceBrowserTest : public InProcessBrowserTest, | 42 class SpellcheckServiceBrowserTest : public InProcessBrowserTest, |
57 public spellcheck::mojom::SpellChecker { | 43 public spellcheck::mojom::SpellChecker { |
58 public: | 44 public: |
59 SpellcheckServiceBrowserTest() : binding_(this) {} | 45 SpellcheckServiceBrowserTest() : binding_(this) {} |
60 | 46 |
61 void SetUpOnMainThread() override { | 47 void SetUpOnMainThread() override { |
62 renderer_.reset(new content::MockRenderProcessHost(GetContext())); | 48 renderer_.reset(new content::MockRenderProcessHost(GetContext())); |
63 prefs_ = user_prefs::UserPrefs::Get(GetContext()); | 49 prefs_ = user_prefs::UserPrefs::Get(GetContext()); |
64 } | 50 } |
65 | 51 |
66 void TearDownOnMainThread() override { | 52 void TearDownOnMainThread() override { |
67 binding_.Close(); | 53 binding_.Close(); |
68 prefs_ = nullptr; | 54 prefs_ = nullptr; |
69 renderer_.reset(); | 55 renderer_.reset(); |
70 } | 56 } |
71 | 57 |
72 BrowserContext* GetContext() { | 58 RenderProcessHost* GetRenderer() const { return renderer_.get(); } |
| 59 |
| 60 BrowserContext* GetContext() const { |
73 return static_cast<BrowserContext*>(browser()->profile()); | 61 return static_cast<BrowserContext*>(browser()->profile()); |
74 } | 62 } |
75 | 63 |
76 PrefService* GetPrefs() { | 64 PrefService* GetPrefs() const { return prefs_; } |
77 return prefs_; | |
78 } | |
79 | 65 |
80 void InitSpellcheck(bool enable_spellcheck, | 66 void InitSpellcheck(bool enable_spellcheck, |
81 const std::string& single_dictionary, | 67 const std::string& single_dictionary, |
82 const std::string& multiple_dictionaries) { | 68 const std::string& multiple_dictionaries) { |
83 prefs_->SetBoolean(spellcheck::prefs::kEnableSpellcheck, | 69 prefs_->SetBoolean(spellcheck::prefs::kEnableSpellcheck, |
84 enable_spellcheck); | 70 enable_spellcheck); |
85 prefs_->SetString(spellcheck::prefs::kSpellCheckDictionary, | 71 prefs_->SetString(spellcheck::prefs::kSpellCheckDictionary, |
86 single_dictionary); | 72 single_dictionary); |
87 base::ListValue dictionaries_value; | 73 base::ListValue dictionaries_value; |
88 dictionaries_value.AppendStrings( | 74 dictionaries_value.AppendStrings( |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 } | 187 } |
202 | 188 |
203 void CustomDictionaryChanged( | 189 void CustomDictionaryChanged( |
204 const std::vector<std::string>& words_added, | 190 const std::vector<std::string>& words_added, |
205 const std::vector<std::string>& words_removed) override { | 191 const std::vector<std::string>& words_removed) override { |
206 custom_dictionary_changed_called_ = true; | 192 custom_dictionary_changed_called_ = true; |
207 EXPECT_EQ(1u, words_removed.size()); | 193 EXPECT_EQ(1u, words_removed.size()); |
208 EXPECT_EQ(2u, words_added.size()); | 194 EXPECT_EQ(2u, words_added.size()); |
209 } | 195 } |
210 | 196 |
| 197 protected: |
| 198 // Quits the RunLoop on SpellChecker request flow completion. |
| 199 base::OnceClosure quit_; |
| 200 |
| 201 private: |
211 // Mocked RenderProcessHost. | 202 // Mocked RenderProcessHost. |
212 std::unique_ptr<content::MockRenderProcessHost> renderer_; | 203 std::unique_ptr<content::MockRenderProcessHost> renderer_; |
213 | 204 |
214 // Not owned preferences service. | 205 // Not owned preferences service. |
215 PrefService* prefs_; | 206 PrefService* prefs_; |
216 | 207 |
217 // Binding to receive the SpellChecker request flow. | 208 // Binding to receive the SpellChecker request flow. |
218 mojo::Binding<spellcheck::mojom::SpellChecker> binding_; | 209 mojo::Binding<spellcheck::mojom::SpellChecker> binding_; |
219 | 210 |
220 // Quits the RunLoop on SpellChecker request flow completion. | |
221 base::OnceClosure quit_; | |
222 | |
223 // Used to verify the SpellChecker request flow. | 211 // Used to verify the SpellChecker request flow. |
224 bool bound_connection_closed_; | 212 bool bound_connection_closed_; |
225 bool custom_dictionary_changed_called_; | 213 bool custom_dictionary_changed_called_; |
226 bool initialize_spellcheck_called_; | 214 bool initialize_spellcheck_called_; |
227 bool spellcheck_enabled_state_; | 215 bool spellcheck_enabled_state_; |
228 | 216 |
229 DISALLOW_COPY_AND_ASSIGN(SpellcheckServiceBrowserTest); | 217 DISALLOW_COPY_AND_ASSIGN(SpellcheckServiceBrowserTest); |
230 }; | 218 }; |
231 | 219 |
| 220 class SpellcheckServiceHostBrowserTest : public SpellcheckServiceBrowserTest { |
| 221 public: |
| 222 SpellcheckServiceHostBrowserTest() = default; |
| 223 |
| 224 void RequestDictionary() { |
| 225 spellcheck::mojom::SpellCheckHostPtr interface; |
| 226 RequestSpellCheckHost(&interface); |
| 227 |
| 228 interface->RequestDictionary(); |
| 229 } |
| 230 |
| 231 void NotifyChecked() { |
| 232 spellcheck::mojom::SpellCheckHostPtr interface; |
| 233 RequestSpellCheckHost(&interface); |
| 234 |
| 235 bool misspelt = true; |
| 236 base::UTF8ToUTF16("hallo", 5, &word_); |
| 237 interface->NotifyChecked(word_, misspelt); |
| 238 base::RunLoop().RunUntilIdle(); |
| 239 } |
| 240 |
| 241 void CallSpellingService() { |
| 242 spellcheck::mojom::SpellCheckHostPtr interface; |
| 243 RequestSpellCheckHost(&interface); |
| 244 |
| 245 base::UTF8ToUTF16("hello", 5, &word_); |
| 246 interface->CallSpellingService( |
| 247 word_, |
| 248 base::Bind(&SpellcheckServiceHostBrowserTest::SpellingServiceDone, |
| 249 base::Unretained(this))); |
| 250 |
| 251 base::RunLoop run_loop; |
| 252 quit_ = run_loop.QuitClosure(); |
| 253 run_loop.Run(); |
| 254 |
| 255 EXPECT_TRUE(spelling_service_done_called_); |
| 256 } |
| 257 |
| 258 private: |
| 259 void RequestSpellCheckHost(spellcheck::mojom::SpellCheckHostPtr* interface) { |
| 260 SpellCheckHostImpl::Create(GetRenderer()->GetID(), |
| 261 service_manager::BindSourceInfo(), |
| 262 mojo::MakeRequest(interface)); |
| 263 } |
| 264 |
| 265 void SpellingServiceDone(bool success, |
| 266 const std::vector<::SpellCheckResult>& results) { |
| 267 spelling_service_done_called_ = true; |
| 268 if (quit_) |
| 269 std::move(quit_).Run(); |
| 270 } |
| 271 |
| 272 bool spelling_service_done_called_ = false; |
| 273 base::string16 word_; |
| 274 |
| 275 DISALLOW_COPY_AND_ASSIGN(SpellcheckServiceHostBrowserTest); |
| 276 }; |
| 277 |
232 // Removing a spellcheck language from accept languages should remove it from | 278 // Removing a spellcheck language from accept languages should remove it from |
233 // spellcheck languages list as well. | 279 // spellcheck languages list as well. |
234 IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest, | 280 IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest, |
235 RemoveSpellcheckLanguageFromAcceptLanguages) { | 281 RemoveSpellcheckLanguageFromAcceptLanguages) { |
236 InitSpellcheck(true, "", "en-US,fr"); | 282 InitSpellcheck(true, "", "en-US,fr"); |
237 SetAcceptLanguages("en-US,es,ru"); | 283 SetAcceptLanguages("en-US,es,ru"); |
238 EXPECT_EQ("en-US", GetMultilingualDictionaries()); | 284 EXPECT_EQ("en-US", GetMultilingualDictionaries()); |
239 } | 285 } |
240 | 286 |
241 // Keeping spellcheck languages in accept languages should not alter spellcheck | 287 // Keeping spellcheck languages in accept languages should not alter spellcheck |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 ChangeCustomDictionary(); | 373 ChangeCustomDictionary(); |
328 EXPECT_TRUE(GetCustomDictionaryChangedState()); | 374 EXPECT_TRUE(GetCustomDictionaryChangedState()); |
329 | 375 |
330 EnableSpellcheck(false); | 376 EnableSpellcheck(false); |
331 EXPECT_FALSE(GetEnableSpellcheckState(true)); | 377 EXPECT_FALSE(GetEnableSpellcheckState(true)); |
332 | 378 |
333 ChangeCustomDictionary(); | 379 ChangeCustomDictionary(); |
334 EXPECT_TRUE(GetCustomDictionaryChangedState()); | 380 EXPECT_TRUE(GetCustomDictionaryChangedState()); |
335 } | 381 } |
336 | 382 |
| 383 // Starting with only a single-language spellcheck setting, the host should |
| 384 // initialize the renderer's spellcheck system, and the same if the renderer |
| 385 // explicity requests the spellcheck dictionaries. |
| 386 IN_PROC_BROWSER_TEST_F(SpellcheckServiceHostBrowserTest, RequestDictionary) { |
| 387 InitSpellcheck(true, "en-US", ""); |
| 388 EXPECT_TRUE(GetEnableSpellcheckState()); |
| 389 |
| 390 RequestDictionary(); |
| 391 EXPECT_TRUE(GetEnableSpellcheckState()); |
| 392 } |
| 393 |
| 394 // When the renderer notifies that it corrected a word, the render process |
| 395 // host should record UMA stats about the correction. |
| 396 IN_PROC_BROWSER_TEST_F(SpellcheckServiceHostBrowserTest, NotifyChecked) { |
| 397 const char kMisspellRatio[] = "SpellCheck.MisspellRatio"; |
| 398 |
| 399 base::HistogramTester tester; |
| 400 tester.ExpectTotalCount(kMisspellRatio, 0); |
| 401 NotifyChecked(); |
| 402 tester.ExpectTotalCount(kMisspellRatio, 1); |
| 403 } |
| 404 |
| 405 #if !BUILDFLAG(USE_BROWSER_SPELLCHECKER) |
| 406 // When the renderer requests the spelling service for correcting text, the |
| 407 // render process host should call the remote spelling service. |
| 408 IN_PROC_BROWSER_TEST_F(SpellcheckServiceHostBrowserTest, CallSpellingService) { |
| 409 CallSpellingService(); |
| 410 } |
| 411 #endif // !BUILDFLAG(USE_BROWSER_SPELLCHECKER) |
| 412 |
337 // Tests that we can delete a corrupted BDICT file used by hunspell. We do not | 413 // Tests that we can delete a corrupted BDICT file used by hunspell. We do not |
338 // run this test on Mac because Mac does not use hunspell by default. | 414 // run this test on Mac because Mac does not use hunspell by default. |
339 IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest, DeleteCorruptedBDICT) { | 415 IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest, DeleteCorruptedBDICT) { |
| 416 // Corrupted BDICT data: please do not use this BDICT data for other tests. |
| 417 const uint8_t kCorruptedBDICT[] = { |
| 418 0x42, 0x44, 0x69, 0x63, 0x02, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, |
| 419 0x3b, 0x00, 0x00, 0x00, 0x65, 0x72, 0xe0, 0xac, 0x27, 0xc7, 0xda, 0x66, |
| 420 0x6d, 0x1e, 0xa6, 0x35, 0xd1, 0xf6, 0xb7, 0x35, 0x32, 0x00, 0x00, 0x00, |
| 421 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, |
| 422 0x0a, 0x0a, 0x41, 0x46, 0x20, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, |
| 423 0x49, 0x00, 0x68, 0x02, 0x73, 0x06, 0x74, 0x0b, 0x77, 0x11, 0x79, 0x15, |
| 424 }; |
| 425 |
340 // Write the corrupted BDICT data to create a corrupted BDICT file. | 426 // Write the corrupted BDICT data to create a corrupted BDICT file. |
341 base::FilePath dict_dir; | 427 base::FilePath dict_dir; |
342 ASSERT_TRUE(PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir)); | 428 ASSERT_TRUE(PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir)); |
343 base::FilePath bdict_path = | 429 base::FilePath bdict_path = |
344 spellcheck::GetVersionedFileName("en-US", dict_dir); | 430 spellcheck::GetVersionedFileName("en-US", dict_dir); |
345 | 431 |
346 { | 432 { |
347 base::ThreadRestrictions::ScopedAllowIO allow_io; | 433 base::ThreadRestrictions::ScopedAllowIO allow_io; |
348 size_t actual = base::WriteFile( | 434 size_t actual = base::WriteFile( |
349 bdict_path, reinterpret_cast<const char*>(kCorruptedBDICT), | 435 bdict_path, reinterpret_cast<const char*>(kCorruptedBDICT), |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
466 std::string pref; | 552 std::string pref; |
467 ASSERT_TRUE(GetPrefs() | 553 ASSERT_TRUE(GetPrefs() |
468 ->GetList(spellcheck::prefs::kSpellCheckDictionaries) | 554 ->GetList(spellcheck::prefs::kSpellCheckDictionaries) |
469 ->GetString(0, &pref)); | 555 ->GetString(0, &pref)); |
470 EXPECT_EQ("en-US", pref); | 556 EXPECT_EQ("en-US", pref); |
471 ASSERT_TRUE(GetPrefs() | 557 ASSERT_TRUE(GetPrefs() |
472 ->GetList(spellcheck::prefs::kSpellCheckDictionaries) | 558 ->GetList(spellcheck::prefs::kSpellCheckDictionaries) |
473 ->GetString(1, &pref)); | 559 ->GetString(1, &pref)); |
474 EXPECT_EQ("fr", pref); | 560 EXPECT_EQ("fr", pref); |
475 } | 561 } |
OLD | NEW |